Split root and cluster frames in smaller pieces (#5737)

* Make root frame child components comply with open closed principle and include it in the behavioural unit tests

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

* Make cluster frame child components comply with open closed principle and include it in behavioural unit tests

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

* Remove duplication

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

* Simplify test

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

* Make a component more determistic in unit tests

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

* Mock uninterested, non-deterministic third party library in unit tests

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

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

* Optimize registration of injectables in unit tests to make tests faster

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

* Update snapshots

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

* Remove import time side-effect causing memory leak

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne SavolainenandMikko Aspiala authored and GitHub committed 2022-07-04 09:38:29 -07:00
1 parent 1a9fa699c9
commit 14d5a1c3cc
66 files changed
+48472 -35711

No files matched your search

@@ -3,71 +3,206 @@
exports[`extension special characters in page registrations renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="app-update-not-available"
data-testid="welcome-banner-container"
style="width: 320px;"
>
No new updates available
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
@@ -78,74 +213,126 @@ exports[`extension special characters in page registrations renders 1`] = `
exports[`extension special characters in page registrations when navigating to route with ID having special characters renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
class="items"
>
<div
data-testid="app-update-not-available"
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
No new updates available
<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>
<main>
<div
id="lens-views"
/>
<div>
Some page
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
Some page
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
File diff suppressed because it is too large. Load diff
@@ -3,78 +3,130 @@
exports[`navigating between routes given route with optional path parameters when navigating to route with path parameters renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
class="items"
>
<div
data-testid="app-update-not-available"
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
No new updates available
</div>
<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="rightSide"
data-testid="status-bar-right"
/>
</div>
<pre>
{
<main>
<div
id="lens-views"
/>
<pre>
{
"someParameter": "some-value",
"someOtherParameter": "some-other-value"
}
</pre>
</pre>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
@@ -84,74 +136,126 @@ exports[`navigating between routes given route with optional path parameters whe
exports[`navigating between routes given route without path parameters when navigating to route renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
class="items"
>
<div
data-testid="app-update-not-available"
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
No new updates available
<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>
<main>
<div
id="lens-views"
/>
<div>
Some component
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div>
Some component
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
@@ -3,71 +3,206 @@
exports[`add-cluster - navigation using application menu renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="app-update-not-available"
data-testid="welcome-banner-container"
style="width: 320px;"
>
No new updates available
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
@@ -78,151 +213,203 @@ exports[`add-cluster - navigation using application menu renders 1`] = `
exports[`add-cluster - navigation using application menu when navigating to add cluster using application menu renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
class="items"
>
<div
data-testid="app-update-not-available"
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="SettingLayout AddClusters"
data-testid="add-cluster-page"
>
<div
class="contentRegion"
id="ScrollSpyRoot"
>
<div
class="content flex column gaps"
>
<h2>
Add Clusters from Kubeconfig
</h2>
<p>
Clusters added here are
<b>
not
</b>
merged into the
<code>
~/.kube/config
</code>
file.
<a
href="https://docs.k8slens.dev/main/catalog/add-cluster/"
rel="noreferrer"
target="_blank"
<span
class="icon"
data-icon-name="home"
>
Read more about adding clusters.
</a>
</p>
<div
class="flex column"
/>
<div
class="actions-panel"
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<button
class="Button primary"
disabled=""
type="button"
<span
class="icon"
data-icon-name="arrow_back"
>
Add clusters
</button>
</div>
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="toolsRegion"
class="items"
/>
</div>
<main>
<div
id="lens-views"
/>
<div
class="SettingLayout AddClusters"
data-testid="add-cluster-page"
>
<div
class="fixed top-[60px]"
class="contentRegion"
id="ScrollSpyRoot"
>
<div>
<div
aria-label="Close"
class="closeButton"
role="button"
>
<i
class="Icon icon material focusable"
<div
class="content flex column gaps"
>
<h2>
Add Clusters from Kubeconfig
</h2>
<p>
Clusters added here are
<b>
not
</b>
merged into the
<code>
~/.kube/config
</code>
file.
<a
href="https://docs.k8slens.dev/main/catalog/add-cluster/"
rel="noreferrer"
target="_blank"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
Read more about adding clusters.
</a>
</p>
<div
aria-hidden="true"
class="esc"
class="flex column"
/>
<div
class="actions-panel"
>
ESC
<button
class="Button primary"
disabled=""
type="button"
>
Add clusters
</button>
</div>
</div>
<div
class="toolsRegion"
>
<div
class="fixed top-[60px]"
>
<div>
<div
aria-label="Close"
class="closeButton"
role="button"
>
<i
class="Icon icon material focusable"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
<div
aria-hidden="true"
class="esc"
>
ESC
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
@@ -9,10 +9,6 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import React from "react";
// TODO: Make components free of side effects by making them deterministic
jest.mock("../../renderer/components/tooltip/tooltip", () => ({
Tooltip: () => null,
}));
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
withTooltip: (Target: any) => ({ tooltip, tooltipOverrideDisabled, ...props }: any) => <Target {...props} />,
}));
@@ -4,71 +4,206 @@ exports[`encourage user to update when sufficient time passed since update was d
<body>
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="app-update-not-available"
data-testid="welcome-banner-container"
style="width: 320px;"
>
No new updates available
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -4,71 +4,206 @@ exports[`periodical checking of updates given updater is enabled and configurati
<body>
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="app-update-not-available"
data-testid="welcome-banner-container"
style="width: 320px;"
>
No new updates available
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
@@ -4,71 +4,206 @@ exports[`selection of update stability when started renders 1`] = `
<body>
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="app-update-not-available"
data-testid="welcome-banner-container"
style="width: 320px;"
>
No new updates available
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -22,6 +22,7 @@ import pathExistsInjectable from "../../common/fs/path-exists.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
import sidebarStorageInjectable from "../../renderer/components/layout/sidebar-storage/sidebar-storage.injectable";
import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
describe("cluster - sidebar and tab navigation for core", () => {
@@ -38,6 +39,8 @@ describe("cluster - sidebar and tab navigation for core", () => {
applicationBuilder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
rendererDi.override(
directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage",
@@ -94,7 +97,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{
sidebar: {
expanded: { "some-parent-id": true },
@@ -136,7 +139,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{
sidebar: {
expanded: { "some-unknown-parent-id": true },
@@ -166,7 +169,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{
someThingButSidebar: {},
},
@@ -268,7 +271,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const pathExistsFake = rendererDi.inject(pathExistsInjectable);
const actual = await pathExistsFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
);
expect(actual).toBe(false);
@@ -280,7 +283,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable);
const actual = await readJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
);
expect(actual).toEqual({
@@ -18,8 +18,14 @@ import { navigateToRouteInjectionToken } from "../../common/front-end-routing/na
import assert from "assert";
import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
// TODO: Make tooltips free of side effects by making it deterministic
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
withTooltip: (target: any) => target,
}));
describe("cluster - sidebar and tab navigation for extensions", () => {
let applicationBuilder: ApplicationBuilder;
let rendererDi: DiContainer;
@@ -34,6 +40,8 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
applicationBuilder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
rendererDi.override(
directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage",
@@ -96,7 +104,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{
sidebar: {
expanded: { "some-extension-name-some-parent-id": true },
@@ -132,7 +140,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{
sidebar: {
expanded: { "some-extension-name-some-unknown-parent-id": true },
@@ -162,7 +170,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{
someThingButSidebar: {},
},
@@ -284,7 +292,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const pathExistsFake = rendererDi.inject(pathExistsInjectable);
const actual = await pathExistsFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
);
expect(actual).toBe(false);
@@ -296,7 +304,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable);
const actual = await readJsonFileFake(
"/some-directory-for-lens-local-storage/app.json",
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
);
expect(actual).toEqual({
@@ -3,71 +3,206 @@
exports[`extensions - navigation using application menu renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="app-update-not-available"
data-testid="welcome-banner-container"
style="width: 320px;"
>
No new updates available
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
@@ -78,184 +213,236 @@ exports[`extensions - navigation using application menu renders 1`] = `
exports[`extensions - navigation using application menu when navigating to extensions using application menu renders 1`] = `
<div>
<div
class="topBar"
class="ClusterManager"
>
<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"
class="topBar"
>
<div
class="item"
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>
<main>
<div
id="lens-views"
/>
<div
class="SettingLayout DropFileInput Extensions"
data-testid="extensions-page"
>
<div
data-testid="app-update-not-available"
class="contentRegion"
id="ScrollSpyRoot"
>
No new updates available
</div>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
<div
class="SettingLayout DropFileInput Extensions"
data-testid="extensions-page"
>
<div
class="contentRegion"
id="ScrollSpyRoot"
>
<div
class="content"
>
<section>
<h1>
Extensions
</h1>
<div
class="notice mb-14 mt-3"
class="content"
>
<p>
Add new features via Lens Extensions. Check out the
<a
href="https://docs.k8slens.dev/main/extensions/"
rel="noreferrer"
target="_blank"
>
docs
</a>
and list of
<a
href="https://github.com/lensapp/lens-extensions/blob/main/README.md"
rel="noreferrer"
target="_blank"
>
available extensions
</a>
.
</p>
</div>
<section
class="mt-2"
>
<div
class="SubTitle"
>
Name or file path or URL to an extension package (tar, tgz)
</div>
<div
class="flex"
>
<section>
<h1>
Extensions
</h1>
<div
class="flex-1"
/>
<div
class="flex-initial"
class="notice mb-14 mt-3"
>
<button
class="Button w-80 h-full primary"
type="button"
<p>
Add new features via Lens Extensions. Check out the
<a
href="https://docs.k8slens.dev/main/extensions/"
rel="noreferrer"
target="_blank"
>
docs
</a>
and list of
<a
href="https://github.com/lensapp/lens-extensions/blob/main/README.md"
rel="noreferrer"
target="_blank"
>
available extensions
</a>
.
</p>
</div>
<section
class="mt-2"
>
<div
class="SubTitle"
>
Install
</button>
Name or file path or URL to an extension package (tar, tgz)
</div>
<div
class="flex"
>
<div
class="flex-1"
/>
<div
class="flex-initial"
>
<button
class="Button w-80 h-full primary"
type="button"
>
Install
</button>
</div>
</div>
<small
class="mt-3"
>
<b>
Pro-Tip
</b>
: you can drag-n-drop tarball-file to this area
</small>
</section>
<div>
<div
class="Spinner singleColor center"
/>
</div>
</section>
</div>
<div
class="toolsRegion"
>
<div
class="fixed top-[60px]"
>
<div>
<div
aria-label="Close"
class="closeButton"
role="button"
>
<i
class="Icon icon material focusable"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
<div
aria-hidden="true"
class="esc"
>
ESC
</div>
</div>
</div>
<small
class="mt-3"
>
<b>
Pro-Tip
</b>
: you can drag-n-drop tarball-file to this area
</small>
</section>
<div>
<div
class="Spinner singleColor center"
/>
</div>
</section>
</div>
<div
class="toolsRegion"
>
<div
class="fixed top-[60px]"
>
<div>
<div
aria-label="Close"
class="closeButton"
role="button"
>
<i
class="Icon icon material focusable"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
</i>
</div>
<div
aria-hidden="true"
class="esc"
>
ESC
</div>
</div>
</div>
</div>
</main>
<div
class="HotbarMenu flex column"
>
<div
class="HotbarItems flex column gaps"
/>
<div
class="HotbarSelector"
>
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
class="HotbarIndex"
>
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</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>
<div
class="rightSide"
data-testid="status-bar-right"
/>
</div>
</div>
<div
@@ -3,451 +3,586 @@
exports[`helm-charts - navigation to Helm charts when navigating to Helm charts renders 1`] = `
<div>
<div
class="flex flex-col"
data-testid="cluster-sidebar"
>
<div
class="SidebarCluster"
>
<div
class="Avatar rounded loadingAvatar"
style="width: 40px; height: 40px;"
>
??
</div>
<div
class="loadingClusterName"
/>
</div>
<div
class="sidebarNav sidebar-active-status"
>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-workloads"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-workloads"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span
class="link-text box grow"
>
Workloads
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-config"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-config"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="list"
>
list
</span>
</i>
<span
class="link-text box grow"
>
Config
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-network"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-network"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="device_hub"
>
device_hub
</span>
</i>
<span
class="link-text box grow"
>
Network
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-storage"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-storage"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="storage"
>
storage
</span>
</i>
<span
class="link-text box grow"
>
Storage
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="true"
data-testid="sidebar-item-helm"
>
<a
aria-current="page"
class="nav-item flex gaps align-center expandable active"
data-testid="sidebar-item-link-for-helm"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span
class="link-text box grow"
>
Helm
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-user-management"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-user-management"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="security"
>
security
</span>
</i>
<span
class="link-text box grow"
>
Access Control
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-custom-resources"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-custom-resources"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="extension"
>
extension
</span>
</i>
<span
class="link-text box grow"
>
Custom Resources
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
</div>
</div>
class="Notifications flex column align-flex-end"
/>
<div
class="TabLayout"
data-testid="tab-layout"
class="mainLayout"
style="--sidebar-width: 200px;"
>
<div
class="Tabs center scrollable"
class="sidebar"
>
<div
class="Tab flex gaps align-center active"
data-is-active-test="true"
data-testid="tab-link-for-charts"
role="tab"
tabindex="0"
class="flex flex-col"
data-testid="cluster-sidebar"
>
<div
class="label"
>
Charts
</div>
</div>
<div
class="Tab flex gaps align-center"
data-is-active-test="false"
data-testid="tab-link-for-releases"
role="tab"
tabindex="0"
>
<div
class="label"
>
Releases
</div>
</div>
</div>
<main>
<div
data-testid="page-for-helm-charts"
style="display: none;"
/>
<div
class="ItemListLayout flex column HelmCharts"
>
<div
class="header flex gaps align-center"
class="SidebarCluster"
>
<div
class="Input SearchInput focused"
class="Avatar rounded loadingAvatar"
style="width: 40px; height: 40px;"
>
<label
class="input-area flex gaps align-center"
id=""
??
</div>
<div
class="loadingClusterName"
/>
</div>
<div
class="sidebarNav sidebar-active-status"
>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-workloads"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-workloads"
href="/"
>
<input
class="input box grow"
placeholder="Search Helm Charts..."
spellcheck="false"
value=""
/>
<i
class="Icon material focusable small"
class="Icon svg focusable"
>
<span
class="icon"
data-icon-name="search"
/>
</i>
<span
class="link-text box grow"
>
Workloads
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
search
keyboard_arrow_down
</span>
</i>
</label>
<div
class="input-info flex gaps"
/>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-config"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-config"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="list"
>
list
</span>
</i>
<span
class="link-text box grow"
>
Config
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-network"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-network"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="device_hub"
>
device_hub
</span>
</i>
<span
class="link-text box grow"
>
Network
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-storage"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-storage"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="storage"
>
storage
</span>
</i>
<span
class="link-text box grow"
>
Storage
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="true"
data-testid="sidebar-item-helm"
>
<a
aria-current="page"
class="nav-item flex gaps align-center expandable active"
data-testid="sidebar-item-link-for-helm"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span
class="link-text box grow"
>
Helm
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-user-management"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-user-management"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="security"
>
security
</span>
</i>
<span
class="link-text box grow"
>
Access Control
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-custom-resources"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-custom-resources"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="extension"
>
extension
</span>
</i>
<span
class="link-text box grow"
>
Custom Resources
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
</div>
</div>
<div
class="ResizingAnchor horizontal trailing"
/>
</div>
<div
class="contents"
>
<div
class="TabLayout"
data-testid="tab-layout"
>
<div
class="items box grow flex column"
class="Tabs center scrollable"
>
<div
class="Table flex column HelmCharts box grow dark selectable scrollable sortable autoSize virtual"
class="Tab flex gaps align-center active"
data-is-active-test="true"
data-testid="tab-link-for-charts"
role="tab"
tabindex="0"
>
<div
class="TableHead sticky nowrap topLine"
class="label"
>
Charts
</div>
</div>
<div
class="Tab flex gaps align-center"
data-is-active-test="false"
data-testid="tab-link-for-releases"
role="tab"
tabindex="0"
>
<div
class="label"
>
Releases
</div>
</div>
</div>
<main>
<div
data-testid="page-for-helm-charts"
style="display: none;"
/>
<div
class="ItemListLayout flex column HelmCharts"
>
<div
class="header flex gaps align-center"
>
<div
class="TableCell icon nowrap"
class="Input SearchInput focused"
>
<div
class="content"
/>
</div>
<div
class="TableCell name nowrap sorting"
id="name"
>
<div
class="content"
>
Name
</div>
<i
class="Icon sortIcon material focusable"
>
<span
class="icon"
data-icon-name="arrow_drop_down"
>
arrow_drop_down
</span>
</i>
</div>
<div
class="TableCell description nowrap"
id="description"
>
<div
class="content"
>
Description
</div>
</div>
<div
class="TableCell version nowrap"
id="version"
>
<div
class="content"
>
Version
</div>
</div>
<div
class="TableCell app-version nowrap"
id="app-version"
>
<div
class="content"
>
App Version
</div>
</div>
<div
class="TableCell repository nowrap sorting"
id="repo"
>
<div
class="content"
>
Repository
</div>
<i
class="Icon sortIcon material focusable"
>
<span
class="icon"
data-icon-name="arrow_drop_down"
>
arrow_drop_down
</span>
</i>
</div>
<div
class="TableCell menu nowrap"
>
<div
class="content"
<label
class="input-area flex gaps align-center"
id=""
>
<input
class="input box grow"
placeholder="Search Helm Charts..."
spellcheck="false"
value=""
/>
<i
class="Icon material interactive focusable"
id="menu_actions_17"
tabindex="0"
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="more_vert"
data-icon-name="search"
>
more_vert
search
</span>
</i>
</div>
</label>
<div
class="input-info flex gaps"
/>
</div>
</div>
<div
class="NoItems flex box grow"
class="items box grow flex column"
>
<div
class="box center"
class="Table flex column HelmCharts box grow dark selectable scrollable sortable autoSize virtual"
>
Item list is empty
<div
class="TableHead sticky nowrap topLine"
>
<div
class="TableCell icon nowrap"
>
<div
class="content"
/>
</div>
<div
class="TableCell name nowrap sorting"
id="name"
>
<div
class="content"
>
Name
</div>
<i
class="Icon sortIcon material focusable"
>
<span
class="icon"
data-icon-name="arrow_drop_down"
>
arrow_drop_down
</span>
</i>
</div>
<div
class="TableCell description nowrap"
id="description"
>
<div
class="content"
>
Description
</div>
</div>
<div
class="TableCell version nowrap"
id="version"
>
<div
class="content"
>
Version
</div>
</div>
<div
class="TableCell app-version nowrap"
id="app-version"
>
<div
class="content"
>
App Version
</div>
</div>
<div
class="TableCell repository nowrap sorting"
id="repo"
>
<div
class="content"
>
Repository
</div>
<i
class="Icon sortIcon material focusable"
>
<span
class="icon"
data-icon-name="arrow_drop_down"
>
arrow_drop_down
</span>
</i>
</div>
<div
class="TableCell menu nowrap"
>
<div
class="content"
>
<i
class="Icon material interactive focusable"
id="menu_actions_27"
tabindex="0"
>
<span
class="icon"
data-icon-name="more_vert"
>
more_vert
</span>
</i>
</div>
</div>
</div>
<div
class="NoItems flex box grow"
>
<div
class="box center"
>
Item list is empty
</div>
</div>
</div>
<div
class="AddRemoveButtons flex gaps"
/>
</div>
</div>
</main>
</div>
</div>
<div
class="footer"
>
<div
class="Dock"
tabindex="-1"
>
<div
class="ResizingAnchor vertical leading"
/>
<div
class="tabs-container flex align-center"
>
<div
class="dockTabs"
role="tablist"
>
<div
class="Tabs tabs"
>
<div
class="Tab flex gaps align-center DockTab TerminalTab active"
id="tab-terminal"
role="tab"
tabindex="0"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="terminal"
>
terminal
</span>
</i>
<div
class="label"
>
<div
class="flex align-center"
>
<span
class="title"
>
Terminal
</span>
<div
class="close"
>
<i
class="Icon material interactive focusable small"
id="tooltip_target_13"
tabindex="0"
>
<span
class="icon"
data-icon-name="close"
>
close
</span>
<div />
</i>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="AddRemoveButtons flex gaps"
/>
class="toolbar flex gaps align-center box grow"
>
<div
class="dock-menu box grow"
>
<i
class="Icon new-dock-tab material interactive focusable"
id="menu_actions_14"
tabindex="0"
>
<span
class="icon"
data-icon-name="add"
>
add
</span>
<div />
</i>
</div>
<i
class="Icon material interactive focusable"
id="tooltip_target_16"
tabindex="0"
>
<span
class="icon"
data-icon-name="fullscreen"
>
fullscreen
</span>
<div />
</i>
<i
class="Icon material interactive focusable"
id="tooltip_target_17"
tabindex="0"
>
<span
class="icon"
data-icon-name="keyboard_arrow_up"
>
keyboard_arrow_up
</span>
<div />
</i>
</div>
</div>
</div>
</main>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
</div>
`;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -4,115 +4,250 @@ exports[`status-bar-items-originating-from-extensions when application starts wh
<body>
<div>
<div
class="topBar"
class="ClusterManager"
>
<div
class="items"
class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
<div
class="items"
>
<span
class="icon"
data-icon-name="home"
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
arrow_forward
</span>
</i>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<main>
<div
id="lens-views"
/>
<div
class="flex justify-center Welcome align-center"
data-testid="welcome-page"
>
<div
data-testid="welcome-banner-container"
style="width: 320px;"
>
<i
class="Icon logo svg focusable"
>
<span
class="icon"
/>
</i>
<div
class="flex justify-center"
>
<div
data-testid="welcome-text-container"
style="width: 320px;"
>
<h2>
Welcome to OpenLens 5!
</h2>
<p>
To get you started we have auto-detected your clusters in your
kubeconfig file and added them to the catalog, your centralized
view for managing all your cloud-native resources.
<br />
<br />
If you have any questions or feedback, please join our
<a
class="link"
href="https://join.slack.com/t/k8slens/shared_invite/zt-wcl8jq3k-68R5Wcmk1o95MLBE5igUDQ"
rel="noreferrer"
target="_blank"
>
Lens Community slack channel
</a>
.
</p>
<ul
class="block"
data-testid="welcome-menu-container"
style="width: 320px;"
>
<li
class="flex grid-12"
>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="view_list"
>
view_list
</span>
</i>
<a
class="box col-10"
>
Browse Clusters in Catalog
</a>
<i
class="Icon box col-1 material focusable"
>
<span
class="icon"
data-icon-name="navigate_next"
>
navigate_next
</span>
</i>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
class="HotbarMenu flex column"
>
<div
class="item"
>
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
class="HotbarItems flex column gaps"
/>
<div
class="item"
class="HotbarSelector"
>
<div
data-testid="some-testId"
<i
class="Icon Icon previous material interactive focusable"
tabindex="0"
>
left1
</div>
</div>
<div
class="item"
>
<span
class="icon"
data-icon-name="arrow_left"
>
arrow_left
</span>
</i>
<div
data-testid="some-testId"
class="HotbarIndex"
>
left2
<div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div>
</div>
<div
class="rightSide"
data-testid="status-bar-right"
class="StatusBar"
>
<div
class="item"
class="leftSide"
data-testid="status-bar-left"
>
<div
data-testid="some-testId"
class="item"
>
right3
<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="item"
class="rightSide"
data-testid="status-bar-right"
>
<span
data-testid="some-testId"
<div
class="item"
>
right2
</span>
</div>
<div
class="item"
>
<span
data-testid="some-testId"
<div
data-testid="some-testId"
>
right3
</div>
</div>
<div
class="item"
>
right1
</span>
<span
data-testid="some-testId"
>
right2
</span>
</div>
<div
class="item"
>
<span
data-testid="some-testId"
>
right1
</span>
</div>
</div>
</div>
</div>
File diff suppressed because it is too large. Load diff
@@ -21,25 +21,41 @@ describe("welcome - navigation using application menu", () => {
expect(rendered.container).toMatchSnapshot();
});
it("does not show welcome page yet", () => {
const actual = rendered.queryByTestId("welcome-page");
it("shows welcome page being front page", () => {
const actual = rendered.getByTestId("welcome-page");
expect(actual).toBeNull();
expect(actual).not.toBeNull();
});
describe("when navigating to welcome using application menu", () => {
describe("when navigated somewhere else", () => {
beforeEach(() => {
applicationBuilder.applicationMenu.click("help.welcome");
applicationBuilder.applicationMenu.click("root.preferences");
});
it("renders", () => {
expect(rendered.container).toMatchSnapshot();
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows welcome page", () => {
const actual = rendered.getByTestId("welcome-page");
it("does not show welcome page", () => {
const actual = rendered.queryByTestId("welcome-page");
expect(actual).not.toBeNull();
expect(actual).toBeNull();
});
describe("when navigated to welcome using application menu", () => {
beforeEach(() => {
applicationBuilder.applicationMenu.click("help.welcome");
});
it("renders", () => {
expect(rendered.container).toMatchSnapshot();
});
it("shows welcome page", () => {
const actual = rendered.getByTestId("welcome-page");
expect(actual).not.toBeNull();
});
});
});
});
+15 -10
View File
@@ -4,7 +4,7 @@
*/
import glob from "glob";
import { kebabCase, memoize, noop } from "lodash/fp";
import { kebabCase, memoize, noop, chunk } from "lodash/fp";
import type { DiContainer, Injectable } from "@ogre-tools/injectable";
import { createContainer } from "@ogre-tools/injectable";
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
@@ -99,6 +99,7 @@ import updateHelmReleaseInjectable from "./helm/helm-service/update-helm-release
import waitUntilBundledExtensionsAreLoadedInjectable from "./start-main-application/lens-window/application-window/wait-until-bundled-extensions-are-loaded.injectable";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import electronInjectable from "./utils/resolve-system-proxy/electron.injectable";
import type { HotbarStore } from "../common/hotbars/store";
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
const {
@@ -111,15 +112,13 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
setLegacyGlobalDiForExtensionApi(di, Environments.main);
for (const filePath of getInjectableFilePaths()) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const injectableInstance = require(filePath).default;
const filePaths = getInjectableFilePaths();
di.register({
...injectableInstance,
aliases: [injectableInstance, ...(injectableInstance.aliases || [])],
});
}
const injectables = filePaths.map(filePath => require(filePath).default);
chunk(100)(injectables).forEach(chunkInjectables => {
di.register(...chunkInjectables);
});
di.preventSideEffects();
@@ -127,7 +126,13 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
di.override(electronInjectable, () => ({}));
di.override(waitUntilBundledExtensionsAreLoadedInjectable, () => async () => {});
di.override(getRandomIdInjectable, () => () => "some-irrelevant-random-id");
di.override(hotbarStoreInjectable, () => ({ load: () => {} }));
di.override(hotbarStoreInjectable, () => ({
load: () => {},
getActive: () => ({ name: "some-hotbar", items: [] }),
getDisplayIndex: () => "0",
}) as unknown as HotbarStore);
di.override(userStoreInjectable, () => ({ startMainReactions: () => {}, extensionRegistryUrl: { customUrl: "some-custom-url" }}) as UserStore);
di.override(extensionsStoreInjectable, () => ({ isEnabled: (opts) => (void opts, false) }) as ExtensionsStore);
di.override(clusterStoreInjectable, () => ({ provideInitialFromMain: () => {}, getById: (id) => (void id, {}) as Cluster }) as ClusterStore);
@@ -0,0 +1,24 @@
/**
* 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 { CronJobTriggerDialog } from "./cronjob-trigger-dialog";
import { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const cronJobTriggerDialogClusterFrameChildComponentInjectable = getInjectable({
id: "cron-job-trigger-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "cron-job-trigger-dialog",
shouldRender: computed(() => true),
Component: CronJobTriggerDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default cronJobTriggerDialogClusterFrameChildComponentInjectable;
@@ -0,0 +1,24 @@
/**
* 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 { DeploymentScaleDialog } from "./dialog";
import { clusterFrameChildComponentInjectionToken } from "../../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const deploymentScaleDialogClusterFrameChildComponentInjectable = getInjectable({
id: "deployment-scale-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "deployment-scale-dialog",
shouldRender: computed(() => true),
Component: DeploymentScaleDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default deploymentScaleDialogClusterFrameChildComponentInjectable;
@@ -0,0 +1,24 @@
/**
* 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 { clusterFrameChildComponentInjectionToken } from "../../../frames/cluster-frame/cluster-frame-child-component-injection-token";
import { ReplicaSetScaleDialog } from "./dialog";
const replicasetScaleDialogClusterFrameChildComponentInjectable = getInjectable({
id: "replicaset-scale-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "replicaset-scale-dialog",
shouldRender: computed(() => true),
Component: ReplicaSetScaleDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default replicasetScaleDialogClusterFrameChildComponentInjectable;
@@ -0,0 +1,24 @@
/**
* 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 { StatefulSetScaleDialog } from "./dialog";
import { clusterFrameChildComponentInjectionToken } from "../../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const statefulsetScaleDialogClusterFrameChildComponentInjectable = getInjectable({
id: "statefulset-scale-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "statefulset-scale-dialog",
shouldRender: computed(() => true),
Component: StatefulSetScaleDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default statefulsetScaleDialogClusterFrameChildComponentInjectable;
@@ -0,0 +1,30 @@
/**
* 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 { rootFrameChildComponentInjectionToken } from "../../frames/root-frame/root-frame-child-component-injection-token";
import { ClusterManager } from "./cluster-manager";
import { computed } from "mobx";
import { ErrorBoundary } from "../error-boundary";
const clusterManagerRootFrameChildComponentInjectable = getInjectable({
id: "cluster-manager-root-frame-child-component",
instantiate: () => ({
id: "cluster-manager",
shouldRender: computed(() => true),
Component: () => (
<ErrorBoundary>
<ClusterManager />
</ErrorBoundary>
),
}),
injectionToken: rootFrameChildComponentInjectionToken,
});
export default clusterManagerRootFrameChildComponentInjectable;
@@ -0,0 +1,24 @@
/**
* 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 { CommandContainer } from "./command-container";
import { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const commandContainerClusterFrameChildComponentInjectable = getInjectable({
id: "command-container-cluster-frame-child-component",
instantiate: () => ({
id: "command-container",
shouldRender: computed(() => true),
Component: CommandContainer,
}),
causesSideEffects: true,
injectionToken: clusterFrameChildComponentInjectionToken,
});
export default commandContainerClusterFrameChildComponentInjectable;
@@ -0,0 +1,24 @@
/**
* 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 { rootFrameChildComponentInjectionToken } from "../../frames/root-frame/root-frame-child-component-injection-token";
import { computed } from "mobx";
import { CommandContainer } from "./command-container";
const commandContainerRootFrameChildComponentInjectable = getInjectable({
id: "command-container-root-frame-child-component",
instantiate: () => ({
id: "command-container",
shouldRender: computed(() => true),
Component: CommandContainer,
}),
causesSideEffects: true,
injectionToken: rootFrameChildComponentInjectionToken,
});
export default commandContainerRootFrameChildComponentInjectable;
@@ -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 { ConfirmDialog } from "./confirm-dialog";
import { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const confirmDialogClusterFrameChildComponentInjectable = getInjectable({
id: "confirm-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "confirm-dialog",
shouldRender: computed(() => true),
Component: ConfirmDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
});
export default confirmDialogClusterFrameChildComponentInjectable;
@@ -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 { rootFrameChildComponentInjectionToken } from "../../frames/root-frame/root-frame-child-component-injection-token";
import { computed } from "mobx";
import { ConfirmDialog } from "./confirm-dialog";
const confirmDialogRootFrameChildComponentInjectable = getInjectable({
id: "confirm-dialog-root-frame-child-component",
instantiate: () => ({
id: "confirm-dialog",
shouldRender: computed(() => true),
Component: ConfirmDialog,
}),
injectionToken: rootFrameChildComponentInjectionToken,
});
export default confirmDialogRootFrameChildComponentInjectable;
@@ -7,9 +7,7 @@ import { KubeConfig } from "@kubernetes/client-node";
import { fireEvent } from "@testing-library/react";
import type { RenderResult } from "@testing-library/react";
import mockFs from "mock-fs";
import React from "react";
import * as selectEvent from "react-select-event";
import { DeleteClusterDialog } from "../view";
import type { CreateCluster } from "../../../../common/cluster/create-cluster-injection-token";
import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token";
import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable";
@@ -19,12 +17,6 @@ import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-cre
import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable";
import type { ApplicationBuilder } from "../../test-utils/get-application-builder";
import { getApplicationBuilder } from "../../test-utils/get-application-builder";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import { routeSpecificComponentInjectionToken } from "../../../routes/route-specific-component-injection-token";
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
import normalizedPlatformInjectable from "../../../../common/vars/normalized-platform.injectable";
import kubectlBinaryNameInjectable from "../../../../main/kubectl/binary-name.injectable";
import kubectlDownloadingNormalizedArchInjectable from "../../../../main/kubectl/normalized-arch.injectable";
@@ -111,22 +103,9 @@ describe("<DeleteClusterDialog />", () => {
mainDi.override(kubectlBinaryNameInjectable, () => "kubectl");
mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
mainDi.override(normalizedPlatformInjectable, () => "darwin");
rendererDi.override(hotbarStoreInjectable, () => ({}));
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
});
const { rendererDi } = applicationBuilder.dis;
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
applicationBuilder.beforeRender(({ rendererDi }) => {
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
const testRoute = rendererDi.inject(testRouteInjectable);
navigateToRoute(testRoute);
});
mockFs();
applicationBuilder.beforeRender(({ rendererDi }) => {
@@ -321,26 +300,3 @@ describe("<DeleteClusterDialog />", () => {
});
});
});
const testRouteInjectable = getInjectable({
id: "some-test-route",
instantiate: () => ({
path: "/some-test-path",
clusterFrame: false,
isEnabled: computed(() => true),
}),
injectionToken: frontEndRouteInjectionToken,
});
const testRouteComponentInjectable = getInjectable({
id: "some-test-component",
instantiate: (di) => ({
route: di.inject(testRouteInjectable),
Component: () => <DeleteClusterDialog />,
}),
injectionToken: routeSpecificComponentInjectionToken,
});
@@ -0,0 +1,24 @@
/**
* 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 { DeleteClusterDialog } from "./view";
import { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const deleteClusterDialogClusterFrameChildComponentInjectable = getInjectable({
id: "delete-cluster-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "delete-cluster-dialog",
shouldRender: computed(() => true),
Component: DeleteClusterDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default deleteClusterDialogClusterFrameChildComponentInjectable;
+5 -3
View File
@@ -14,10 +14,10 @@ import { Tab } from "../tabs";
import { Icon } from "../icon";
import { Menu, MenuItem } from "../menu";
import { observable } from "mobx";
import { isMac } from "../../../common/vars";
import { withInjectables } from "@ogre-tools/injectable-react";
import dockStoreInjectable from "./dock/store.injectable";
import { Tooltip, TooltipPosition } from "../tooltip";
import isMacInjectable from "../../../common/vars/is-mac.injectable";
export interface DockTabProps extends TabProps<DockTabModel> {
moreActions?: React.ReactNode;
@@ -25,6 +25,7 @@ export interface DockTabProps extends TabProps<DockTabModel> {
interface Dependencies {
dockStore: DockStore;
isMac: boolean;
}
@observer
@@ -73,7 +74,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
}
render() {
const { className, moreActions, dockStore, active, ...tabProps } = this.props;
const { className, moreActions, dockStore, active, isMac, ...tabProps } = this.props;
if (!tabProps.value) {
return;
@@ -100,7 +101,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
<Icon
small
material="close"
tooltip={`Close ${isMac ? "⌘+W" : "Ctrl+W"}`}
tooltip={`Close ${this.props.isMac ? "⌘+W" : "Ctrl+W"}`}
onClick={close}
/>
</div>
@@ -124,6 +125,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
export const DockTab = withInjectables<Dependencies, DockTabProps>(NonInjectedDockTab, {
getProps: (di, props) => ({
dockStore: di.inject(dockStoreInjectable),
isMac: di.inject(isMacInjectable),
...props,
}),
});
@@ -184,7 +184,9 @@ class NonInjectedHotbarMenu extends React.Component<Dependencies & HotbarMenuPro
return (
<div className={cssNames("HotbarMenu flex column", { draggingOver: this.draggingOver }, className)}>
<div className="HotbarItems flex column gaps">
<DragDropContext onDragStart={() => this.onDragStart()} onDragEnd={(result) => this.onDragEnd(result)}>
<DragDropContext
onDragStart={() => this.onDragStart()}
onDragEnd={(result) => this.onDragEnd(result)}>
{this.renderGrid()}
</DragDropContext>
</div>
@@ -0,0 +1,24 @@
/**
* 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 { KubeObjectDetails } from "./kube-object-details";
import { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const kubeObjectDetailsClusterFrameChildComponentInjectable = getInjectable({
id: "kube-object-details-cluster-frame-child-component",
instantiate: () => ({
id: "kube-object-details",
shouldRender: computed(() => true),
Component: KubeObjectDetails,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default kubeObjectDetailsClusterFrameChildComponentInjectable;
@@ -0,0 +1,24 @@
/**
* 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 { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
import { KubeConfigDialog } from "./kubeconfig-dialog";
const kubeconfigDialogClusterFrameChildComponentInjectable = getInjectable({
id: "kubeconfig-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "kubeconfig-dialog",
shouldRender: computed(() => true),
Component: KubeConfigDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default kubeconfigDialogClusterFrameChildComponentInjectable;
@@ -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 { Notifications } from "./notifications";
import { clusterFrameChildComponentInjectionToken } from "../../frames/cluster-frame/cluster-frame-child-component-injection-token";
const notificationsClusterFrameChildComponentInjectable = getInjectable({
id: "notifications-cluster-frame-child-component",
instantiate: () => ({
id: "notifications",
shouldRender: computed(() => true),
Component: Notifications,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
});
export default notificationsClusterFrameChildComponentInjectable;
@@ -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 { rootFrameChildComponentInjectionToken } from "../../frames/root-frame/root-frame-child-component-injection-token";
import { computed } from "mobx";
import { Notifications } from "./notifications";
const notificationsRootFrameChildComponentInjectable = getInjectable({
id: "notifications-root-frame-child-component",
instantiate: () => ({
id: "notifications",
shouldRender: computed(() => true),
Component: Notifications,
}),
injectionToken: rootFrameChildComponentInjectionToken,
});
export default notificationsRootFrameChildComponentInjectable;
@@ -7,21 +7,17 @@ import rendererExtensionsInjectable from "../../../extensions/renderer-extension
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
import type { IObservableArray, ObservableSet } from "mobx";
import { computed, observable, runInAction } from "mobx";
import { renderFor } from "./renderFor";
import React from "react";
import { Router } from "react-router";
import { Observer } from "mobx-react";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import allowedResourcesInjectable from "../../cluster-frame-context/allowed-resources.injectable";
import type { RenderResult } from "@testing-library/react";
import { getByText, fireEvent } from "@testing-library/react";
import type { KubeResource } from "../../../common/rbac";
import { Sidebar } from "../layout/sidebar";
import type { DiContainer } from "@ogre-tools/injectable";
import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable";
import type { ClusterStore } from "../../../common/cluster-store/cluster-store";
import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable";
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
import { pipeline } from "@ogre-tools/fp";
import { flatMap, compact, join, get, filter, map, matches, last } from "lodash/fp";
import preferenceNavigationItemsInjectable from "../+preferences/preferences-navigation/preference-navigation-items.injectable";
@@ -44,8 +40,6 @@ import historyInjectable from "../../navigation/history.injectable";
import type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/electron-tray.injectable";
import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable";
import applicationWindowInjectable from "../../../main/start-main-application/lens-window/application-window/application-window.injectable";
import { Notifications } from "../notifications/notifications";
import broadcastThatRootFrameIsRenderedInjectable from "../../frames/root-frame/broadcast-that-root-frame-is-rendered.injectable";
import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting";
import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting";
import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels";
@@ -53,7 +47,6 @@ import trayIconPathsInjectable from "../../../main/tray/tray-icon-path.injectabl
import assert from "assert";
import { openMenu } from "react-select-event";
import userEvent from "@testing-library/user-event";
import { StatusBar } from "../status-bar/status-bar";
import lensProxyPortInjectable from "../../../main/lens-proxy/lens-proxy-port.injectable";
import type { Route } from "../../../common/front-end-routing/front-end-route-injection-token";
import type { NavigateToRouteOptions } from "../../../common/front-end-routing/navigate-to-route-injection-token";
@@ -62,7 +55,10 @@ import type { LensMainExtension } from "../../../extensions/lens-main-extension"
import type { LensExtension } from "../../../extensions/lens-extension";
import extensionInjectable from "../../../extensions/extension-loader/extension/extension.injectable";
import { TopBar } from "../layout/top-bar/top-bar";
import { renderFor } from "./renderFor";
import { RootFrame } from "../../frames/root-frame/root-frame";
import { ClusterFrame } from "../../frames/cluster-frame/cluster-frame";
import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable";
type Callback = (dis: DiContainers) => void | Promise<void>;
@@ -125,10 +121,7 @@ interface DiContainers {
}
interface Environment {
renderSidebar: () => React.ReactNode;
renderTopBar: () => React.ReactNode;
renderStatusBar: () => React.ReactNode;
beforeRender: () => void;
RootComponent: React.ElementType;
onAllowKubeResource: () => void;
}
@@ -166,17 +159,7 @@ export const getApplicationBuilder = () => {
const environments = {
application: {
renderSidebar: () => null,
renderTopBar: () => <TopBar />,
renderStatusBar: () => <StatusBar />,
beforeRender: () => {
const nofifyThatRootFrameIsRendered = rendererDi.inject(broadcastThatRootFrameIsRenderedInjectable);
nofifyThatRootFrameIsRendered();
},
RootComponent: RootFrame,
onAllowKubeResource: () => {
throw new Error(
@@ -186,10 +169,7 @@ export const getApplicationBuilder = () => {
} as Environment,
clusterFrame: {
renderSidebar: () => <Sidebar />,
renderStatusBar: () => null,
renderTopBar: () => null,
beforeRender: () => {},
RootComponent: ClusterFrame,
onAllowKubeResource: () => {},
} as Environment,
};
@@ -401,6 +381,7 @@ export const getApplicationBuilder = () => {
const namespaceStoreStub = {
contextNamespaces: [],
items: [],
} as unknown as NamespaceStore;
const clusterFrameContextFake = new ClusterFrameContext(
@@ -413,6 +394,7 @@ export const getApplicationBuilder = () => {
rendererDi.override(namespaceStoreInjectable, () => namespaceStoreStub);
rendererDi.override(hostedClusterInjectable, () => clusterStub);
rendererDi.override(hostedClusterIdInjectable, () => "irrelevant-hosted-cluster-id");
rendererDi.override(clusterFrameContextInjectable, () => clusterFrameContextFake);
// Todo: get rid of global state.
@@ -474,35 +456,17 @@ export const getApplicationBuilder = () => {
await startFrame();
const render = renderFor(rendererDi);
const history = rendererDi.inject(historyInjectable);
const currentRouteComponent = rendererDi.inject(currentRouteComponentInjectable);
for (const callback of beforeRenderCallbacks) {
await callback(dis);
}
environment.beforeRender();
const history = rendererDi.inject(historyInjectable);
const render = renderFor(rendererDi);
rendered = render(
<Router history={history}>
{environment.renderSidebar()}
{environment.renderTopBar()}
{environment.renderStatusBar()}
<Observer>
{() => {
const Component = currentRouteComponent.get();
if (!Component) {
return null;
}
return <Component />;
}}
</Observer>
<Notifications />
<environment.RootComponent />
</Router>,
);
@@ -2,6 +2,9 @@
exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissions given no matching component given current url is starting url renders 1`] = `
<div>
<div
class="Notifications flex column align-flex-end"
/>
<div
class="mainLayout"
style="--sidebar-width: 200px;"
@@ -467,14 +470,14 @@ exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissio
</div>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
</div>
`;
exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissions renders 1`] = `
<div>
<div
class="Notifications flex column align-flex-end"
/>
<div
class="mainLayout"
style="--sidebar-width: 200px;"
@@ -947,14 +950,14 @@ exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissio
</div>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
</div>
`;
exports[`<ClusterFrame /> given cluster without list nodes, but with namespaces permissions renders 1`] = `
<div>
<div
class="Notifications flex column align-flex-end"
/>
<div
class="mainLayout"
style="--sidebar-width: 200px;"
@@ -1483,8 +1486,5 @@ exports[`<ClusterFrame /> given cluster without list nodes, but with namespaces
</div>
</div>
</div>
<div
class="Notifications flex column align-flex-end"
/>
</div>
`;
@@ -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";
export interface ClusterFrameChildComponent {
id: string;
Component: React.ElementType;
shouldRender: IComputedValue<boolean>;
}
export const clusterFrameChildComponentInjectionToken = getInjectionToken<ClusterFrameChildComponent>({
id: "cluster-frame-child-component",
});
@@ -0,0 +1,61 @@
/**
* 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 { clusterFrameChildComponentInjectionToken } from "./cluster-frame-child-component-injection-token";
import { MainLayout } from "../../components/layout/main-layout";
import { Sidebar } from "../../components/layout/sidebar";
import { Dock } from "../../components/dock";
import styles from "./cluster-frame.module.css";
import { computed } from "mobx";
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
import { Redirect } from "react-router";
import startUrlInjectable from "./start-url.injectable";
import currentPathInjectable from "../../routes/current-path.injectable";
import { observer } from "mobx-react";
const clusterFrameLayoutChildComponentInjectable = getInjectable({
id: "cluster-frame-layout-child-component",
instantiate: (di) => {
const currentRouteComponent = di.inject(currentRouteComponentInjectable);
const startUrl = di.inject(startUrlInjectable);
const currentPath = di.inject(currentPathInjectable);
return {
id: "cluster-frame-layout",
shouldRender: computed(() => true),
Component: observer(() => {
const Component = currentRouteComponent.get();
const starting = startUrl.get();
const current = currentPath.get();
return (
<MainLayout sidebar={<Sidebar />} footer={<Dock />}>
{Component ? (
<Component />
) : // NOTE: this check is to prevent an infinite loop
starting !== current ? (
<Redirect to={startUrl.get()} />
) : (
<div className={styles.centering}>
<div className="error">
An error has occured. No route can be found matching the
current route, which is also the starting route.
</div>
</div>
)}
</MainLayout>
);
}),
};
},
injectionToken: clusterFrameChildComponentInjectionToken,
});
export default clusterFrameLayoutChildComponentInjectable;
@@ -2,52 +2,30 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "./cluster-frame.module.css";
import React, { useEffect } from "react";
import type { IComputedValue } from "mobx";
import { observer } from "mobx-react";
import { Redirect } from "react-router";
import { ConfirmDialog } from "../../components/confirm-dialog";
import { DeploymentScaleDialog } from "../../components/+workloads-deployments/scale/dialog";
import { CronJobTriggerDialog } from "../../components/+workloads-cronjobs/cronjob-trigger-dialog";
import { StatefulSetScaleDialog } from "../../components/+workloads-statefulsets/scale/dialog";
import { ReplicaSetScaleDialog } from "../../components/+workloads-replicasets/scale-dialog/dialog";
import { CommandContainer } from "../../components/command-palette/command-container";
import { Observer, observer } from "mobx-react";
import { ErrorBoundary } from "../../components/error-boundary";
import { MainLayout } from "../../components/layout/main-layout";
import { Notifications } from "../../components/notifications";
import { KubeObjectDetails } from "../../components/kube-object-details";
import { KubeConfigDialog } from "../../components/kubeconfig-dialog";
import { Sidebar } from "../../components/layout/sidebar";
import { Dock } from "../../components/dock";
import { PortForwardDialog } from "../../port-forward";
import { DeleteClusterDialog } from "../../components/delete-cluster-dialog";
import type { NamespaceStore } from "../../components/+namespaces/store";
import { withInjectables } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "../../components/+namespaces/store.injectable";
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
import { disposer } from "../../utils";
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
import startUrlInjectable from "./start-url.injectable";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import currentPathInjectable from "../../routes/current-path.injectable";
import type { ClusterFrameChildComponent } from "./cluster-frame-child-component-injection-token";
import { clusterFrameChildComponentInjectionToken } from "./cluster-frame-child-component-injection-token";
import watchHistoryStateInjectable from "../../remote-helpers/watch-history-state.injectable";
interface Dependencies {
namespaceStore: NamespaceStore;
currentRouteComponent: IComputedValue<React.ElementType<{}> | undefined>;
startUrl: IComputedValue<string>;
subscribeStores: SubscribeStores;
currentPath: IComputedValue<string>;
childComponents: ClusterFrameChildComponent[];
watchHistoryState: () => () => void;
}
export const NonInjectedClusterFrame = observer(({
namespaceStore,
currentRouteComponent,
startUrl,
subscribeStores,
currentPath,
childComponents,
watchHistoryState,
}: Dependencies) => {
useEffect(() => disposer(
@@ -57,43 +35,14 @@ export const NonInjectedClusterFrame = observer(({
watchHistoryState(),
), []);
const Component = currentRouteComponent.get();
const starting = startUrl.get();
const current = currentPath.get();
return (
<ErrorBoundary>
<MainLayout
sidebar={<Sidebar />}
footer={<Dock />}
>
{
Component
? <Component />
// NOTE: this check is to prevent an infinite loop
: starting !== current
? <Redirect to={startUrl.get()} />
: (
<div className={styles.centering}>
<div className="error">
An error has occured. No route can be found matching the current route, which is also the starting route.
</div>
</div>
)
}
</MainLayout>
<Notifications />
<ConfirmDialog />
<KubeObjectDetails />
<KubeConfigDialog />
<DeploymentScaleDialog />
<StatefulSetScaleDialog />
<ReplicaSetScaleDialog />
<CronJobTriggerDialog />
<PortForwardDialog />
<DeleteClusterDialog />
<CommandContainer />
{childComponents
.map((child) => (
<Observer key={child.id}>
{() => (child.shouldRender.get() ? <child.Component /> : null) }
</Observer>
))}
</ErrorBoundary>
);
});
@@ -102,9 +51,7 @@ export const ClusterFrame = withInjectables<Dependencies>(NonInjectedClusterFram
getProps: di => ({
namespaceStore: di.inject(namespaceStoreInjectable),
subscribeStores: di.inject(subscribeStoresInjectable),
startUrl: di.inject(startUrlInjectable),
currentRouteComponent: di.inject(currentRouteComponentInjectable),
currentPath: di.inject(currentPathInjectable),
childComponents: di.injectMany(clusterFrameChildComponentInjectionToken),
watchHistoryState: di.inject(watchHistoryStateInjectable),
}),
});
@@ -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";
export interface RootFrameChildComponent {
id: string;
Component: React.ElementType;
shouldRender: IComputedValue<boolean>;
}
export const rootFrameChildComponentInjectionToken = getInjectionToken<RootFrameChildComponent>({
id: "root-frame-child-component",
});
+11 -17
View File
@@ -3,25 +3,18 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { injectSystemCAs } from "../../../common/system-ca";
import React from "react";
import { observer } from "mobx-react";
import { ClusterManager } from "../../components/cluster-manager";
import { ErrorBoundary } from "../../components/error-boundary";
import { Notifications } from "../../components/notifications";
import { ConfirmDialog } from "../../components/confirm-dialog";
import { CommandContainer } from "../../components/command-palette/command-container";
import { Observer } from "mobx-react";
import { withInjectables } from "@ogre-tools/injectable-react";
import broadcastThatRootFrameIsRenderedInjectable from "./broadcast-that-root-frame-is-rendered.injectable";
// Todo: remove import-time side-effect.
injectSystemCAs();
import type { RootFrameChildComponent } from "./root-frame-child-component-injection-token";
import { rootFrameChildComponentInjectionToken } from "./root-frame-child-component-injection-token";
interface Dependencies {
broadcastThatRootFrameIsRendered: () => void;
childComponents: RootFrameChildComponent[];
}
@observer
class NonInjectedRootFrame extends React.Component<Dependencies> {
static displayName = "RootFrame";
@@ -32,12 +25,12 @@ class NonInjectedRootFrame extends React.Component<Dependencies> {
render() {
return (
<>
<ErrorBoundary>
<ClusterManager />
</ErrorBoundary>
<Notifications />
<ConfirmDialog />
<CommandContainer />
{this.props.childComponents
.map((child) => (
<Observer key={child.id}>
{() => (child.shouldRender.get() ? <child.Component /> : null) }
</Observer>
))}
</>
);
}
@@ -49,6 +42,7 @@ export const RootFrame = withInjectables<Dependencies>(
{
getProps: (di, props) => ({
broadcastThatRootFrameIsRendered: di.inject(broadcastThatRootFrameIsRenderedInjectable),
childComponents: di.injectMany(rootFrameChildComponentInjectionToken),
...props,
}),
},
@@ -0,0 +1,23 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { injectSystemCAs } from "../../../common/system-ca";
import { getInjectable } from "@ogre-tools/injectable";
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
const setupSystemCaInjectable = getInjectable({
id: "setup-system-ca",
instantiate: () => ({
run: async () => {
await injectSystemCAs();
},
}),
causesSideEffects: true,
injectionToken: beforeFrameStartsInjectionToken,
});
export default setupSystemCaInjectable;
+54 -14
View File
@@ -4,10 +4,8 @@
*/
import glob from "glob";
import { memoize, noop } from "lodash/fp";
import type {
DiContainer,
Injectable } from "@ogre-tools/injectable";
import { memoize, noop, chunk } from "lodash/fp";
import type { DiContainer, Injectable } from "@ogre-tools/injectable";
import {
createContainer,
} from "@ogre-tools/injectable";
@@ -41,7 +39,7 @@ import apiManagerInjectable from "../common/k8s-api/api-manager/manager.injectab
import ipcRendererInjectable from "./utils/channel/ipc-renderer.injectable";
import type { IpcRenderer } from "electron";
import setupOnApiErrorListenersInjectable from "./api/setup-on-api-errors.injectable";
import { observable } from "mobx";
import { observable, computed } from "mobx";
import defaultShellInjectable from "./components/+preferences/default-shell.injectable";
import appVersionInjectable from "../common/get-configuration-file-model/app-version/app-version.injectable";
import provideInitialValuesForSyncBoxesInjectable from "./utils/sync-box/provide-initial-values-for-sync-boxes.injectable";
@@ -59,6 +57,18 @@ import goForwardInjectable from "./components/layout/top-bar/go-forward.injectab
import closeWindowInjectable from "./components/layout/top-bar/close-window.injectable";
import maximizeWindowInjectable from "./components/layout/top-bar/maximize-window.injectable";
import toggleMaximizeWindowInjectable from "./components/layout/top-bar/toggle-maximize-window.injectable";
import commandContainerRootFrameChildComponentInjectable from "./components/command-palette/command-container-root-frame-child-component.injectable";
import type { HotbarStore } from "../common/hotbars/store";
import commandContainerClusterFrameChildComponentInjectable from "./components/command-palette/command-container-cluster-frame-child-component.injectable";
import cronJobTriggerDialogClusterFrameChildComponentInjectable from "./components/+workloads-cronjobs/cron-job-trigger-dialog-cluster-frame-child-component.injectable";
import deploymentScaleDialogClusterFrameChildComponentInjectable from "./components/+workloads-deployments/scale/deployment-scale-dialog-cluster-frame-child-component.injectable";
import replicasetScaleDialogClusterFrameChildComponentInjectable from "./components/+workloads-replicasets/scale-dialog/replicaset-scale-dialog-cluster-frame-child-component.injectable";
import statefulsetScaleDialogClusterFrameChildComponentInjectable from "./components/+workloads-statefulsets/scale/statefulset-scale-dialog-cluster-frame-child-component.injectable";
import deleteClusterDialogClusterFrameChildComponentInjectable from "./components/delete-cluster-dialog/delete-cluster-dialog-cluster-frame-child-component.injectable";
import kubeObjectDetailsClusterFrameChildComponentInjectable from "./components/kube-object-details/kube-object-details-cluster-frame-child-component.injectable";
import kubeconfigDialogClusterFrameChildComponentInjectable from "./components/kubeconfig-dialog/kubeconfig-dialog-cluster-frame-child-component.injectable";
import portForwardDialogClusterFrameChildComponentInjectable from "./port-forward/port-forward-dialog-cluster-frame-child-component.injectable";
import setupSystemCaInjectable from "./frames/root-frame/setup-system-ca.injectable";
export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) => {
const {
@@ -71,14 +81,13 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
for (const filePath of getInjectableFilePaths()) {
const injectableInstance = require(filePath).default;
const filePaths = getInjectableFilePaths();
di.register({
...injectableInstance,
aliases: [injectableInstance, ...(injectableInstance.aliases || [])],
});
}
const injectables = filePaths.map(filePath => require(filePath).default);
chunk(100)(injectables).forEach(chunkInjectables => {
di.register(...chunkInjectables);
});
di.preventSideEffects();
@@ -103,8 +112,35 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
di.override(lensResourcesDirInjectable, () => "/irrelevant");
di.override(watchHistoryStateInjectable, () => () => () => {});
// TODO: Remove side-effects and shared global state
di.override(commandContainerRootFrameChildComponentInjectable, () => ({
Component: () => null,
id: "command-container",
shouldRender: computed(() => false),
}));
// TODO: Remove side-effects and shared global state
const clusterFrameChildComponentInjectables: Injectable<any, any, any>[] = [
commandContainerClusterFrameChildComponentInjectable,
cronJobTriggerDialogClusterFrameChildComponentInjectable,
deploymentScaleDialogClusterFrameChildComponentInjectable,
replicasetScaleDialogClusterFrameChildComponentInjectable,
statefulsetScaleDialogClusterFrameChildComponentInjectable,
deleteClusterDialogClusterFrameChildComponentInjectable,
kubeObjectDetailsClusterFrameChildComponentInjectable,
kubeconfigDialogClusterFrameChildComponentInjectable,
portForwardDialogClusterFrameChildComponentInjectable,
];
clusterFrameChildComponentInjectables.forEach((injectable) => {
di.override(injectable, () => ({
Component: () => null,
id: injectable.id,
shouldRender: computed(() => false),
}));
});
di.override(watchHistoryStateInjectable, () => () => () => {});
di.override(openAppContextMenuInjectable, () => () => {});
di.override(goBackInjectable, () => () => {});
di.override(goForwardInjectable, () => () => {});
@@ -126,13 +162,17 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
// eslint-disable-next-line unused-imports/no-unused-vars-ts
di.override(extensionsStoreInjectable, () => ({ isEnabled: ({ id, isBundled }) => false }) as ExtensionsStore);
di.override(hotbarStoreInjectable, () => ({}));
di.override(hotbarStoreInjectable, () => ({
getActive: () => ({ name: "some-hotbar", items: [] }),
getDisplayIndex: () => "0",
}) as unknown as HotbarStore);
di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore);
// eslint-disable-next-line unused-imports/no-unused-vars-ts
di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore);
di.override(setupSystemCaInjectable, () => ({ run: () => {} }));
di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} }));
di.override(provideInitialValuesForSyncBoxesInjectable, () => ({ run: () => {} }));
@@ -0,0 +1,24 @@
/**
* 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 { PortForwardDialog } from "./port-forward-dialog";
import { clusterFrameChildComponentInjectionToken } from "../frames/cluster-frame/cluster-frame-child-component-injection-token";
const portForwardDialogClusterFrameChildComponentInjectable = getInjectable({
id: "port-forward-dialog-cluster-frame-child-component",
instantiate: () => ({
id: "port-forward-dialog",
shouldRender: computed(() => true),
Component: PortForwardDialog,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
causesSideEffects: true,
});
export default portForwardDialogClusterFrameChildComponentInjectable;