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

+15
View File
@@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React from "react";
import type {
DragDropContextProps,
DraggableProps,
DroppableProps,
} from "react-beautiful-dnd";
export const DragDropContext = ({ children }: DragDropContextProps) => <>{ children }</>;
export const Draggable = ({ children }: DraggableProps) => <>{ children }</>;
export const Droppable = ({ children }: DroppableProps) => <>{ children }</>;
+5 -5
View File
@@ -209,11 +209,11 @@
"@hapi/subtext": "^7.0.4", "@hapi/subtext": "^7.0.4",
"@kubernetes/client-node": "^0.16.3", "@kubernetes/client-node": "^0.16.3",
"@material-ui/styles": "^4.11.5", "@material-ui/styles": "^4.11.5",
"@ogre-tools/fp": "9.0.0", "@ogre-tools/fp": "9.0.1",
"@ogre-tools/injectable": "9.0.0", "@ogre-tools/injectable": "9.0.1",
"@ogre-tools/injectable-extension-for-auto-registration": "9.0.0", "@ogre-tools/injectable-extension-for-auto-registration": "9.0.1",
"@ogre-tools/injectable-extension-for-mobx": "9.0.0", "@ogre-tools/injectable-extension-for-mobx": "9.0.1",
"@ogre-tools/injectable-react": "9.0.0", "@ogre-tools/injectable-react": "9.0.1",
"@sentry/electron": "^3.0.7", "@sentry/electron": "^3.0.7",
"@sentry/integrations": "^6.19.3", "@sentry/integrations": "^6.19.3",
"@side/jest-runtime": "^1.0.1", "@side/jest-runtime": "^1.0.1",
@@ -3,71 +3,206 @@
exports[`extension special characters in page registrations renders 1`] = ` exports[`extension special characters in page registrations renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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>
</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>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <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>
<div <div
class="Notifications flex column align-flex-end" 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`] = ` exports[`extension special characters in page registrations when navigating to route with ID having special characters renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <div
class="item" class="items"
> >
<div <i
data-testid="app-update-not-available" 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> </div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div> </div>
</div> </div>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <div
</div> class="leftSide"
<div> data-testid="status-bar-left"
Some page >
<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>
<div <div
class="Notifications flex column align-flex-end" 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`] = ` exports[`navigating between routes given route with optional path parameters when navigating to route with path parameters renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <div
class="item" class="items"
> >
<div <i
data-testid="app-update-not-available" class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
> >
No new updates available <span
</div> 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>
<div
class="items"
/>
</div> </div>
<div <main>
class="rightSide" <div
data-testid="status-bar-right" id="lens-views"
/> />
</div> <pre>
<pre> {
{
"someParameter": "some-value", "someParameter": "some-value",
"someOtherParameter": "some-other-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 <div
class="Notifications flex column align-flex-end" 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`] = ` exports[`navigating between routes given route without path parameters when navigating to route renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <div
class="item" class="items"
> >
<div <i
data-testid="app-update-not-available" 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> </div>
<i
class="Icon material interactive focusable"
tabindex="0"
>
<span
class="icon"
data-icon-name="arrow_right"
>
arrow_right
</span>
</i>
</div> </div>
</div> </div>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <div
</div> class="leftSide"
<div> data-testid="status-bar-left"
Some component >
<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>
<div <div
class="Notifications flex column align-flex-end" class="Notifications flex column align-flex-end"
@@ -3,71 +3,206 @@
exports[`add-cluster - navigation using application menu renders 1`] = ` exports[`add-cluster - navigation using application menu renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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>
</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>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <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>
<div <div
class="Notifications flex column align-flex-end" 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`] = ` exports[`add-cluster - navigation using application menu when navigating to add cluster using application menu renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <div
class="item" class="items"
> >
<div <i
data-testid="app-update-not-available" class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
> >
No new updates available <span
</div> class="icon"
</div> data-icon-name="home"
</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"
> >
Read more about adding clusters. home
</a> </span>
</p> </i>
<div <i
class="flex column" class="Icon material interactive disabled focusable"
/> data-testid="history-back"
<div
class="actions-panel"
> >
<button <span
class="Button primary" class="icon"
disabled="" data-icon-name="arrow_back"
type="button"
> >
Add clusters arrow_back
</button> </span>
</div> </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>
<div <div
class="toolsRegion" class="items"
/>
</div>
<main>
<div
id="lens-views"
/>
<div
class="SettingLayout AddClusters"
data-testid="add-cluster-page"
> >
<div <div
class="fixed top-[60px]" class="contentRegion"
id="ScrollSpyRoot"
> >
<div> <div
<div class="content flex column gaps"
aria-label="Close" >
class="closeButton" <h2>
role="button" Add Clusters from Kubeconfig
> </h2>
<i <p>
class="Icon icon material focusable" 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 Read more about adding clusters.
class="icon" </a>
data-icon-name="close" </p>
>
close
</span>
</i>
</div>
<div <div
aria-hidden="true" class="flex column"
class="esc" />
<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>
</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> </div>
<div <div
@@ -9,10 +9,6 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import React from "react"; import React from "react";
// TODO: Make components free of side effects by making them deterministic // 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", () => ({ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
withTooltip: (Target: any) => ({ tooltip, tooltipOverrideDisabled, ...props }: any) => <Target {...props} />, 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> <body>
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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>
</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>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <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>
<div <div
class="Notifications flex column align-flex-end" 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> <body>
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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>
</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>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <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>
<div <div
class="Notifications flex column align-flex-end" class="Notifications flex column align-flex-end"
@@ -4,71 +4,206 @@ exports[`selection of update stability when started renders 1`] = `
<body> <body>
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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>
</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>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <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>
<div <div
class="Notifications flex column align-flex-end" 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 readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
import sidebarStorageInjectable from "../../renderer/components/layout/sidebar-storage/sidebar-storage.injectable"; 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"; import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
describe("cluster - sidebar and tab navigation for core", () => { describe("cluster - sidebar and tab navigation for core", () => {
@@ -38,6 +39,8 @@ describe("cluster - sidebar and tab navigation for core", () => {
applicationBuilder.setEnvironmentToClusterFrame(); applicationBuilder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
rendererDi.override( rendererDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
@@ -94,7 +97,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{ {
sidebar: { sidebar: {
expanded: { "some-parent-id": true }, expanded: { "some-parent-id": true },
@@ -136,7 +139,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{ {
sidebar: { sidebar: {
expanded: { "some-unknown-parent-id": true }, expanded: { "some-unknown-parent-id": true },
@@ -166,7 +169,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{ {
someThingButSidebar: {}, someThingButSidebar: {},
}, },
@@ -268,7 +271,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const pathExistsFake = rendererDi.inject(pathExistsInjectable); const pathExistsFake = rendererDi.inject(pathExistsInjectable);
const actual = await pathExistsFake( 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); expect(actual).toBe(false);
@@ -280,7 +283,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable); const readJsonFileFake = rendererDi.inject(readJsonFileInjectable);
const actual = await readJsonFileFake( 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({ expect(actual).toEqual({
@@ -18,8 +18,14 @@ import { navigateToRouteInjectionToken } from "../../common/front-end-routing/na
import assert from "assert"; import assert from "assert";
import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake"; import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } 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"; 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", () => { describe("cluster - sidebar and tab navigation for extensions", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
let rendererDi: DiContainer; let rendererDi: DiContainer;
@@ -34,6 +40,8 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
applicationBuilder.setEnvironmentToClusterFrame(); applicationBuilder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
rendererDi.override( rendererDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
@@ -96,7 +104,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{ {
sidebar: { sidebar: {
expanded: { "some-extension-name-some-parent-id": true }, 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); const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{ {
sidebar: { sidebar: {
expanded: { "some-extension-name-some-unknown-parent-id": true }, 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); const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/app.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
{ {
someThingButSidebar: {}, someThingButSidebar: {},
}, },
@@ -284,7 +292,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const pathExistsFake = rendererDi.inject(pathExistsInjectable); const pathExistsFake = rendererDi.inject(pathExistsInjectable);
const actual = await pathExistsFake( 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); expect(actual).toBe(false);
@@ -296,7 +304,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable); const readJsonFileFake = rendererDi.inject(readJsonFileInjectable);
const actual = await readJsonFileFake( 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({ expect(actual).toEqual({
@@ -3,71 +3,206 @@
exports[`extensions - navigation using application menu renders 1`] = ` exports[`extensions - navigation using application menu renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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>
</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>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right" >
/> <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>
<div <div
class="Notifications flex column align-flex-end" 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`] = ` exports[`extensions - navigation using application menu when navigating to extensions using application menu renders 1`] = `
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
>
<i
class="Icon material interactive focusable"
data-testid="home-button"
tabindex="0"
>
<span
class="icon"
data-icon-name="home"
>
home
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-back"
>
<span
class="icon"
data-icon-name="arrow_back"
>
arrow_back
</span>
</i>
<i
class="Icon material interactive disabled focusable"
data-testid="history-forward"
>
<span
class="icon"
data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <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 <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 <div
class="notice mb-14 mt-3" class="content"
> >
<p> <section>
Add new features via Lens Extensions. Check out the <h1>
<a Extensions
href="https://docs.k8slens.dev/main/extensions/" </h1>
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"
>
<div <div
class="flex-1" class="notice mb-14 mt-3"
/>
<div
class="flex-initial"
> >
<button <p>
class="Button w-80 h-full primary" Add new features via Lens Extensions. Check out the
type="button" <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 Name or file path or URL to an extension package (tar, tgz)
</button>
</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>
</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> </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> </div>
<div <div
@@ -3,451 +3,586 @@
exports[`helm-charts - navigation to Helm charts when navigating to Helm charts renders 1`] = ` exports[`helm-charts - navigation to Helm charts when navigating to Helm charts renders 1`] = `
<div> <div>
<div <div
class="flex flex-col" class="Notifications flex column align-flex-end"
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>
<div <div
class="TabLayout" class="mainLayout"
data-testid="tab-layout" style="--sidebar-width: 200px;"
> >
<div <div
class="Tabs center scrollable" class="sidebar"
> >
<div <div
class="Tab flex gaps align-center active" class="flex flex-col"
data-is-active-test="true" data-testid="cluster-sidebar"
data-testid="tab-link-for-charts"
role="tab"
tabindex="0"
> >
<div <div
class="label" class="SidebarCluster"
>
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 <div
class="Input SearchInput focused" class="Avatar rounded loadingAvatar"
style="width: 40px; height: 40px;"
> >
<label ??
class="input-area flex gaps align-center" </div>
id="" <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 <i
class="Icon material focusable small" class="Icon svg focusable"
> >
<span <span
class="icon" 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> </span>
</i> </i>
</label> </a>
<div </div>
class="input-info flex gaps" <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>
</div>
<div
class="ResizingAnchor horizontal trailing"
/>
</div>
<div
class="contents"
>
<div
class="TabLayout"
data-testid="tab-layout"
>
<div <div
class="items box grow flex column" class="Tabs center scrollable"
> >
<div <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 <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 <div
class="TableCell icon nowrap" class="Input SearchInput focused"
> >
<div <label
class="content" class="input-area flex gaps align-center"
/> id=""
</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"
> >
<input
class="input box grow"
placeholder="Search Helm Charts..."
spellcheck="false"
value=""
/>
<i <i
class="Icon material interactive focusable" class="Icon material focusable small"
id="menu_actions_17"
tabindex="0"
> >
<span <span
class="icon" class="icon"
data-icon-name="more_vert" data-icon-name="search"
> >
more_vert search
</span> </span>
</i> </i>
</div> </label>
<div
class="input-info flex gaps"
/>
</div> </div>
</div> </div>
<div <div
class="NoItems flex box grow" class="items box grow flex column"
> >
<div <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>
</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>
</div> </div>
</main> </div>
</div> </div>
<div
class="Notifications flex column align-flex-end"
/>
</div> </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> <body>
<div> <div>
<div <div
class="topBar" class="ClusterManager"
> >
<div <div
class="items" class="topBar"
> >
<i <div
class="Icon material interactive focusable" class="items"
data-testid="home-button"
tabindex="0"
> >
<span <i
class="icon" class="Icon material interactive focusable"
data-icon-name="home" data-testid="home-button"
tabindex="0"
> >
home <span
</span> class="icon"
</i> data-icon-name="home"
<i >
class="Icon material interactive disabled focusable" home
data-testid="history-back" </span>
> </i>
<span <i
class="icon" class="Icon material interactive disabled focusable"
data-icon-name="arrow_back" data-testid="history-back"
> >
arrow_back <span
</span> class="icon"
</i> data-icon-name="arrow_back"
<i >
class="Icon material interactive disabled focusable" arrow_back
data-testid="history-forward" </span>
> </i>
<span <i
class="icon" class="Icon material interactive disabled focusable"
data-icon-name="arrow_forward" data-testid="history-forward"
> >
arrow_forward <span
</span> class="icon"
</i> data-icon-name="arrow_forward"
>
arrow_forward
</span>
</i>
</div>
<div
class="items"
/>
</div> </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 <div
class="items" class="HotbarMenu flex column"
/>
</div>
<div
class="StatusBar"
>
<div
class="leftSide"
data-testid="status-bar-left"
> >
<div <div
class="item" class="HotbarItems flex column gaps"
> />
<div
data-testid="app-update-not-available"
>
No new updates available
</div>
</div>
<div <div
class="item" class="HotbarSelector"
> >
<div <i
data-testid="some-testId" class="Icon Icon previous material interactive focusable"
tabindex="0"
> >
left1 <span
</div> class="icon"
</div> data-icon-name="arrow_left"
<div >
class="item" arrow_left
> </span>
</i>
<div <div
data-testid="some-testId" class="HotbarIndex"
> >
left2 <div
class="badge Badge small clickable"
id="hotbarIndex"
>
0
</div>
</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> </div>
<div <div
class="rightSide" class="StatusBar"
data-testid="status-bar-right"
> >
<div <div
class="item" class="leftSide"
data-testid="status-bar-left"
> >
<div <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> </div>
<div <div
class="item" class="rightSide"
data-testid="status-bar-right"
> >
<span <div
data-testid="some-testId" class="item"
> >
right2 <div
</span> data-testid="some-testId"
</div> >
<div right3
class="item" </div>
> </div>
<span <div
data-testid="some-testId" 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> </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(); expect(rendered.container).toMatchSnapshot();
}); });
it("does not show welcome page yet", () => { it("shows welcome page being front page", () => {
const actual = rendered.queryByTestId("welcome-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(() => { beforeEach(() => {
applicationBuilder.applicationMenu.click("help.welcome"); applicationBuilder.applicationMenu.click("root.preferences");
}); });
it("renders", () => { it("renders", () => {
expect(rendered.container).toMatchSnapshot(); expect(rendered.baseElement).toMatchSnapshot();
}); });
it("shows welcome page", () => { it("does not show welcome page", () => {
const actual = rendered.getByTestId("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 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 type { DiContainer, Injectable } from "@ogre-tools/injectable";
import { createContainer } 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"; 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 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 { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import electronInjectable from "./utils/resolve-system-proxy/electron.injectable"; import electronInjectable from "./utils/resolve-system-proxy/electron.injectable";
import type { HotbarStore } from "../common/hotbars/store";
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) { export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
const { const {
@@ -111,15 +112,13 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
setLegacyGlobalDiForExtensionApi(di, Environments.main); setLegacyGlobalDiForExtensionApi(di, Environments.main);
for (const filePath of getInjectableFilePaths()) { const filePaths = getInjectableFilePaths();
// eslint-disable-next-line @typescript-eslint/no-var-requires
const injectableInstance = require(filePath).default;
di.register({ const injectables = filePaths.map(filePath => require(filePath).default);
...injectableInstance,
aliases: [injectableInstance, ...(injectableInstance.aliases || [])], chunk(100)(injectables).forEach(chunkInjectables => {
}); di.register(...chunkInjectables);
} });
di.preventSideEffects(); di.preventSideEffects();
@@ -127,7 +126,13 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
di.override(electronInjectable, () => ({})); di.override(electronInjectable, () => ({}));
di.override(waitUntilBundledExtensionsAreLoadedInjectable, () => async () => {}); di.override(waitUntilBundledExtensionsAreLoadedInjectable, () => async () => {});
di.override(getRandomIdInjectable, () => () => "some-irrelevant-random-id"); 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(userStoreInjectable, () => ({ startMainReactions: () => {}, extensionRegistryUrl: { customUrl: "some-custom-url" }}) as UserStore);
di.override(extensionsStoreInjectable, () => ({ isEnabled: (opts) => (void opts, false) }) as ExtensionsStore); di.override(extensionsStoreInjectable, () => ({ isEnabled: (opts) => (void opts, false) }) as ExtensionsStore);
di.override(clusterStoreInjectable, () => ({ provideInitialFromMain: () => {}, getById: (id) => (void id, {}) as Cluster }) as ClusterStore); 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 { fireEvent } from "@testing-library/react";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import mockFs from "mock-fs"; import mockFs from "mock-fs";
import React from "react";
import * as selectEvent from "react-select-event"; import * as selectEvent from "react-select-event";
import { DeleteClusterDialog } from "../view";
import type { CreateCluster } from "../../../../common/cluster/create-cluster-injection-token"; import type { CreateCluster } from "../../../../common/cluster/create-cluster-injection-token";
import { createClusterInjectionToken } 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"; 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 createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable";
import type { ApplicationBuilder } from "../../test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../test-utils/get-application-builder";
import { getApplicationBuilder } 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 normalizedPlatformInjectable from "../../../../common/vars/normalized-platform.injectable";
import kubectlBinaryNameInjectable from "../../../../main/kubectl/binary-name.injectable"; import kubectlBinaryNameInjectable from "../../../../main/kubectl/binary-name.injectable";
import kubectlDownloadingNormalizedArchInjectable from "../../../../main/kubectl/normalized-arch.injectable"; import kubectlDownloadingNormalizedArchInjectable from "../../../../main/kubectl/normalized-arch.injectable";
@@ -111,22 +103,9 @@ describe("<DeleteClusterDialog />", () => {
mainDi.override(kubectlBinaryNameInjectable, () => "kubectl"); mainDi.override(kubectlBinaryNameInjectable, () => "kubectl");
mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64"); mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
mainDi.override(normalizedPlatformInjectable, () => "darwin"); mainDi.override(normalizedPlatformInjectable, () => "darwin");
rendererDi.override(hotbarStoreInjectable, () => ({}));
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true); 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(); mockFs();
applicationBuilder.beforeRender(({ rendererDi }) => { 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 { Icon } from "../icon";
import { Menu, MenuItem } from "../menu"; import { Menu, MenuItem } from "../menu";
import { observable } from "mobx"; import { observable } from "mobx";
import { isMac } from "../../../common/vars";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import dockStoreInjectable from "./dock/store.injectable"; import dockStoreInjectable from "./dock/store.injectable";
import { Tooltip, TooltipPosition } from "../tooltip"; import { Tooltip, TooltipPosition } from "../tooltip";
import isMacInjectable from "../../../common/vars/is-mac.injectable";
export interface DockTabProps extends TabProps<DockTabModel> { export interface DockTabProps extends TabProps<DockTabModel> {
moreActions?: React.ReactNode; moreActions?: React.ReactNode;
@@ -25,6 +25,7 @@ export interface DockTabProps extends TabProps<DockTabModel> {
interface Dependencies { interface Dependencies {
dockStore: DockStore; dockStore: DockStore;
isMac: boolean;
} }
@observer @observer
@@ -73,7 +74,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
} }
render() { render() {
const { className, moreActions, dockStore, active, ...tabProps } = this.props; const { className, moreActions, dockStore, active, isMac, ...tabProps } = this.props;
if (!tabProps.value) { if (!tabProps.value) {
return; return;
@@ -100,7 +101,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
<Icon <Icon
small small
material="close" material="close"
tooltip={`Close ${isMac ? "⌘+W" : "Ctrl+W"}`} tooltip={`Close ${this.props.isMac ? "⌘+W" : "Ctrl+W"}`}
onClick={close} onClick={close}
/> />
</div> </div>
@@ -124,6 +125,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
export const DockTab = withInjectables<Dependencies, DockTabProps>(NonInjectedDockTab, { export const DockTab = withInjectables<Dependencies, DockTabProps>(NonInjectedDockTab, {
getProps: (di, props) => ({ getProps: (di, props) => ({
dockStore: di.inject(dockStoreInjectable), dockStore: di.inject(dockStoreInjectable),
isMac: di.inject(isMacInjectable),
...props, ...props,
}), }),
}); });
@@ -184,7 +184,9 @@ class NonInjectedHotbarMenu extends React.Component<Dependencies & HotbarMenuPro
return ( return (
<div className={cssNames("HotbarMenu flex column", { draggingOver: this.draggingOver }, className)}> <div className={cssNames("HotbarMenu flex column", { draggingOver: this.draggingOver }, className)}>
<div className="HotbarItems flex column gaps"> <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()} {this.renderGrid()}
</DragDropContext> </DragDropContext>
</div> </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 currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
import type { IObservableArray, ObservableSet } from "mobx"; import type { IObservableArray, ObservableSet } from "mobx";
import { computed, observable, runInAction } from "mobx"; import { computed, observable, runInAction } from "mobx";
import { renderFor } from "./renderFor";
import React from "react"; import React from "react";
import { Router } from "react-router"; import { Router } from "react-router";
import { Observer } from "mobx-react";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable"; import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import allowedResourcesInjectable from "../../cluster-frame-context/allowed-resources.injectable"; import allowedResourcesInjectable from "../../cluster-frame-context/allowed-resources.injectable";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import { getByText, fireEvent } from "@testing-library/react"; import { getByText, fireEvent } from "@testing-library/react";
import type { KubeResource } from "../../../common/rbac"; import type { KubeResource } from "../../../common/rbac";
import { Sidebar } from "../layout/sidebar";
import type { DiContainer } from "@ogre-tools/injectable"; import type { DiContainer } from "@ogre-tools/injectable";
import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable"; import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable";
import type { ClusterStore } from "../../../common/cluster-store/cluster-store"; import type { ClusterStore } from "../../../common/cluster-store/cluster-store";
import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable"; import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable";
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
import { pipeline } from "@ogre-tools/fp"; import { pipeline } from "@ogre-tools/fp";
import { flatMap, compact, join, get, filter, map, matches, last } from "lodash/fp"; import { flatMap, compact, join, get, filter, map, matches, last } from "lodash/fp";
import preferenceNavigationItemsInjectable from "../+preferences/preferences-navigation/preference-navigation-items.injectable"; 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 type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/electron-tray.injectable";
import electronTrayInjectable 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 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 getRendererDi } from "../../getDiForUnitTesting";
import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting"; import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting";
import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels"; 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 assert from "assert";
import { openMenu } from "react-select-event"; import { openMenu } from "react-select-event";
import userEvent from "@testing-library/user-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 lensProxyPortInjectable from "../../../main/lens-proxy/lens-proxy-port.injectable";
import type { Route } from "../../../common/front-end-routing/front-end-route-injection-token"; 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"; 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 type { LensExtension } from "../../../extensions/lens-extension";
import extensionInjectable from "../../../extensions/extension-loader/extension/extension.injectable"; 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>; type Callback = (dis: DiContainers) => void | Promise<void>;
@@ -125,10 +121,7 @@ interface DiContainers {
} }
interface Environment { interface Environment {
renderSidebar: () => React.ReactNode; RootComponent: React.ElementType;
renderTopBar: () => React.ReactNode;
renderStatusBar: () => React.ReactNode;
beforeRender: () => void;
onAllowKubeResource: () => void; onAllowKubeResource: () => void;
} }
@@ -166,17 +159,7 @@ export const getApplicationBuilder = () => {
const environments = { const environments = {
application: { application: {
renderSidebar: () => null, RootComponent: RootFrame,
renderTopBar: () => <TopBar />,
renderStatusBar: () => <StatusBar />,
beforeRender: () => {
const nofifyThatRootFrameIsRendered = rendererDi.inject(broadcastThatRootFrameIsRenderedInjectable);
nofifyThatRootFrameIsRendered();
},
onAllowKubeResource: () => { onAllowKubeResource: () => {
throw new Error( throw new Error(
@@ -186,10 +169,7 @@ export const getApplicationBuilder = () => {
} as Environment, } as Environment,
clusterFrame: { clusterFrame: {
renderSidebar: () => <Sidebar />, RootComponent: ClusterFrame,
renderStatusBar: () => null,
renderTopBar: () => null,
beforeRender: () => {},
onAllowKubeResource: () => {}, onAllowKubeResource: () => {},
} as Environment, } as Environment,
}; };
@@ -401,6 +381,7 @@ export const getApplicationBuilder = () => {
const namespaceStoreStub = { const namespaceStoreStub = {
contextNamespaces: [], contextNamespaces: [],
items: [],
} as unknown as NamespaceStore; } as unknown as NamespaceStore;
const clusterFrameContextFake = new ClusterFrameContext( const clusterFrameContextFake = new ClusterFrameContext(
@@ -413,6 +394,7 @@ export const getApplicationBuilder = () => {
rendererDi.override(namespaceStoreInjectable, () => namespaceStoreStub); rendererDi.override(namespaceStoreInjectable, () => namespaceStoreStub);
rendererDi.override(hostedClusterInjectable, () => clusterStub); rendererDi.override(hostedClusterInjectable, () => clusterStub);
rendererDi.override(hostedClusterIdInjectable, () => "irrelevant-hosted-cluster-id");
rendererDi.override(clusterFrameContextInjectable, () => clusterFrameContextFake); rendererDi.override(clusterFrameContextInjectable, () => clusterFrameContextFake);
// Todo: get rid of global state. // Todo: get rid of global state.
@@ -474,35 +456,17 @@ export const getApplicationBuilder = () => {
await startFrame(); await startFrame();
const render = renderFor(rendererDi);
const history = rendererDi.inject(historyInjectable);
const currentRouteComponent = rendererDi.inject(currentRouteComponentInjectable);
for (const callback of beforeRenderCallbacks) { for (const callback of beforeRenderCallbacks) {
await callback(dis); await callback(dis);
} }
environment.beforeRender(); const history = rendererDi.inject(historyInjectable);
const render = renderFor(rendererDi);
rendered = render( rendered = render(
<Router history={history}> <Router history={history}>
{environment.renderSidebar()} <environment.RootComponent />
{environment.renderTopBar()}
{environment.renderStatusBar()}
<Observer>
{() => {
const Component = currentRouteComponent.get();
if (!Component) {
return null;
}
return <Component />;
}}
</Observer>
<Notifications />
</Router>, </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`] = ` exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissions given no matching component given current url is starting url renders 1`] = `
<div> <div>
<div
class="Notifications flex column align-flex-end"
/>
<div <div
class="mainLayout" class="mainLayout"
style="--sidebar-width: 200px;" style="--sidebar-width: 200px;"
@@ -467,14 +470,14 @@ exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissio
</div> </div>
</div> </div>
</div> </div>
<div
class="Notifications flex column align-flex-end"
/>
</div> </div>
`; `;
exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissions renders 1`] = ` exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissions renders 1`] = `
<div> <div>
<div
class="Notifications flex column align-flex-end"
/>
<div <div
class="mainLayout" class="mainLayout"
style="--sidebar-width: 200px;" style="--sidebar-width: 200px;"
@@ -947,14 +950,14 @@ exports[`<ClusterFrame /> given cluster with list nodes and namespaces permissio
</div> </div>
</div> </div>
</div> </div>
<div
class="Notifications flex column align-flex-end"
/>
</div> </div>
`; `;
exports[`<ClusterFrame /> given cluster without list nodes, but with namespaces permissions renders 1`] = ` exports[`<ClusterFrame /> given cluster without list nodes, but with namespaces permissions renders 1`] = `
<div> <div>
<div
class="Notifications flex column align-flex-end"
/>
<div <div
class="mainLayout" class="mainLayout"
style="--sidebar-width: 200px;" style="--sidebar-width: 200px;"
@@ -1483,8 +1486,5 @@ exports[`<ClusterFrame /> given cluster without list nodes, but with namespaces
</div> </div>
</div> </div>
</div> </div>
<div
class="Notifications flex column align-flex-end"
/>
</div> </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. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import styles from "./cluster-frame.module.css";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import type { IComputedValue } from "mobx"; import { Observer, observer } from "mobx-react";
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 { ErrorBoundary } from "../../components/error-boundary"; 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 type { NamespaceStore } from "../../components/+namespaces/store";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "../../components/+namespaces/store.injectable"; import namespaceStoreInjectable from "../../components/+namespaces/store.injectable";
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api"; import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
import { disposer } from "../../utils"; 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 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"; import watchHistoryStateInjectable from "../../remote-helpers/watch-history-state.injectable";
interface Dependencies { interface Dependencies {
namespaceStore: NamespaceStore; namespaceStore: NamespaceStore;
currentRouteComponent: IComputedValue<React.ElementType<{}> | undefined>;
startUrl: IComputedValue<string>;
subscribeStores: SubscribeStores; subscribeStores: SubscribeStores;
currentPath: IComputedValue<string>; childComponents: ClusterFrameChildComponent[];
watchHistoryState: () => () => void; watchHistoryState: () => () => void;
} }
export const NonInjectedClusterFrame = observer(({ export const NonInjectedClusterFrame = observer(({
namespaceStore, namespaceStore,
currentRouteComponent,
startUrl,
subscribeStores, subscribeStores,
currentPath, childComponents,
watchHistoryState, watchHistoryState,
}: Dependencies) => { }: Dependencies) => {
useEffect(() => disposer( useEffect(() => disposer(
@@ -57,43 +35,14 @@ export const NonInjectedClusterFrame = observer(({
watchHistoryState(), watchHistoryState(),
), []); ), []);
const Component = currentRouteComponent.get();
const starting = startUrl.get();
const current = currentPath.get();
return ( return (
<ErrorBoundary> <ErrorBoundary>
<MainLayout {childComponents
sidebar={<Sidebar />} .map((child) => (
footer={<Dock />} <Observer key={child.id}>
> {() => (child.shouldRender.get() ? <child.Component /> : null) }
{ </Observer>
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 />
</ErrorBoundary> </ErrorBoundary>
); );
}); });
@@ -102,9 +51,7 @@ export const ClusterFrame = withInjectables<Dependencies>(NonInjectedClusterFram
getProps: di => ({ getProps: di => ({
namespaceStore: di.inject(namespaceStoreInjectable), namespaceStore: di.inject(namespaceStoreInjectable),
subscribeStores: di.inject(subscribeStoresInjectable), subscribeStores: di.inject(subscribeStoresInjectable),
startUrl: di.inject(startUrlInjectable), childComponents: di.injectMany(clusterFrameChildComponentInjectionToken),
currentRouteComponent: di.inject(currentRouteComponentInjectable),
currentPath: di.inject(currentPathInjectable),
watchHistoryState: di.inject(watchHistoryStateInjectable), 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. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { injectSystemCAs } from "../../../common/system-ca";
import React from "react"; import React from "react";
import { observer } from "mobx-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 { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import broadcastThatRootFrameIsRenderedInjectable from "./broadcast-that-root-frame-is-rendered.injectable"; import broadcastThatRootFrameIsRenderedInjectable from "./broadcast-that-root-frame-is-rendered.injectable";
import type { RootFrameChildComponent } from "./root-frame-child-component-injection-token";
// Todo: remove import-time side-effect. import { rootFrameChildComponentInjectionToken } from "./root-frame-child-component-injection-token";
injectSystemCAs();
interface Dependencies { interface Dependencies {
broadcastThatRootFrameIsRendered: () => void; broadcastThatRootFrameIsRendered: () => void;
childComponents: RootFrameChildComponent[];
} }
@observer
class NonInjectedRootFrame extends React.Component<Dependencies> { class NonInjectedRootFrame extends React.Component<Dependencies> {
static displayName = "RootFrame"; static displayName = "RootFrame";
@@ -32,12 +25,12 @@ class NonInjectedRootFrame extends React.Component<Dependencies> {
render() { render() {
return ( return (
<> <>
<ErrorBoundary> {this.props.childComponents
<ClusterManager /> .map((child) => (
</ErrorBoundary> <Observer key={child.id}>
<Notifications /> {() => (child.shouldRender.get() ? <child.Component /> : null) }
<ConfirmDialog /> </Observer>
<CommandContainer /> ))}
</> </>
); );
} }
@@ -49,6 +42,7 @@ export const RootFrame = withInjectables<Dependencies>(
{ {
getProps: (di, props) => ({ getProps: (di, props) => ({
broadcastThatRootFrameIsRendered: di.inject(broadcastThatRootFrameIsRenderedInjectable), broadcastThatRootFrameIsRendered: di.inject(broadcastThatRootFrameIsRenderedInjectable),
childComponents: di.injectMany(rootFrameChildComponentInjectionToken),
...props, ...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 glob from "glob";
import { memoize, noop } from "lodash/fp"; import { memoize, noop, chunk } from "lodash/fp";
import type { import type { DiContainer, Injectable } from "@ogre-tools/injectable";
DiContainer,
Injectable } from "@ogre-tools/injectable";
import { import {
createContainer, createContainer,
} from "@ogre-tools/injectable"; } 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 ipcRendererInjectable from "./utils/channel/ipc-renderer.injectable";
import type { IpcRenderer } from "electron"; import type { IpcRenderer } from "electron";
import setupOnApiErrorListenersInjectable from "./api/setup-on-api-errors.injectable"; 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 defaultShellInjectable from "./components/+preferences/default-shell.injectable";
import appVersionInjectable from "../common/get-configuration-file-model/app-version/app-version.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"; 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 closeWindowInjectable from "./components/layout/top-bar/close-window.injectable";
import maximizeWindowInjectable from "./components/layout/top-bar/maximize-window.injectable"; import maximizeWindowInjectable from "./components/layout/top-bar/maximize-window.injectable";
import toggleMaximizeWindowInjectable from "./components/layout/top-bar/toggle-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 } = {}) => { export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) => {
const { const {
@@ -71,14 +81,13 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
setLegacyGlobalDiForExtensionApi(di, Environments.renderer); setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
for (const filePath of getInjectableFilePaths()) { const filePaths = getInjectableFilePaths();
const injectableInstance = require(filePath).default;
di.register({ const injectables = filePaths.map(filePath => require(filePath).default);
...injectableInstance,
aliases: [injectableInstance, ...(injectableInstance.aliases || [])], chunk(100)(injectables).forEach(chunkInjectables => {
}); di.register(...chunkInjectables);
} });
di.preventSideEffects(); di.preventSideEffects();
@@ -103,8 +112,35 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
di.override(lensResourcesDirInjectable, () => "/irrelevant"); 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(openAppContextMenuInjectable, () => () => {});
di.override(goBackInjectable, () => () => {}); di.override(goBackInjectable, () => () => {});
di.override(goForwardInjectable, () => () => {}); di.override(goForwardInjectable, () => () => {});
@@ -126,13 +162,17 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
// eslint-disable-next-line unused-imports/no-unused-vars-ts // eslint-disable-next-line unused-imports/no-unused-vars-ts
di.override(extensionsStoreInjectable, () => ({ isEnabled: ({ id, isBundled }) => false }) as ExtensionsStore); 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); di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore);
// eslint-disable-next-line unused-imports/no-unused-vars-ts // eslint-disable-next-line unused-imports/no-unused-vars-ts
di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore); di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore);
di.override(setupSystemCaInjectable, () => ({ run: () => {} }));
di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} })); di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} }));
di.override(provideInitialValuesForSyncBoxesInjectable, () => ({ 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;
+27 -27
View File
@@ -1211,46 +1211,46 @@
"@nodelib/fs.scandir" "2.1.5" "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0" fastq "^1.6.0"
"@ogre-tools/fp@9.0.0", "@ogre-tools/fp@^9.0.0": "@ogre-tools/fp@9.0.1", "@ogre-tools/fp@^9.0.1":
version "9.0.0" version "9.0.1"
resolved "https://registry.yarnpkg.com/@ogre-tools/fp/-/fp-9.0.0.tgz#926cd4f13b52961156161feeeafddf22a0ad39c0" resolved "https://registry.yarnpkg.com/@ogre-tools/fp/-/fp-9.0.1.tgz#22c23bd209f6f56bf66a5ff4514930334a3a4782"
integrity sha512-kMUgzhdjHuph0UWteOfyXNGBavZJX23NOA5su6fx9NdTzWhl9yB5Uf6Q//nOvL9COftjZDwnAgIaDU4MPdjyqA== integrity sha512-7kORUcvR9DZz5/2qDSSKExGeisXzfmOafP+Z6l8C+WQXEmEQm7CmFMyBEyMkei0eNFzNghlKYgRFpsvBdU3KAg==
dependencies: dependencies:
lodash "^4.17.21" lodash "^4.17.21"
"@ogre-tools/injectable-extension-for-auto-registration@9.0.0": "@ogre-tools/injectable-extension-for-auto-registration@9.0.1":
version "9.0.0" version "9.0.1"
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-auto-registration/-/injectable-extension-for-auto-registration-9.0.0.tgz#69463737ef4f7777db4703964b8a72a5fb82d6b3" resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-auto-registration/-/injectable-extension-for-auto-registration-9.0.1.tgz#e00dff5bd833068faa58d8fa514b218515c55775"
integrity sha512-+3I9Z0GfA04zZoj7Nw5WhJLDFLJgr5xv8Kp1zPDuT9/OvE9EA6hzAqakMDLbvn1zZOJjkJCGk44x6UjSQJp/9w== integrity sha512-reyhW2wWPrNnGXo88QKWUsLyhjF195i0/iXfdAoR8/4lRxWmzka58bc8r6jFvTBBJ6eXaGidhUa5DqZe+Oia2Q==
dependencies: dependencies:
"@ogre-tools/fp" "^9.0.0" "@ogre-tools/fp" "^9.0.1"
"@ogre-tools/injectable" "^9.0.0" "@ogre-tools/injectable" "^9.0.1"
lodash "^4.17.21" lodash "^4.17.21"
"@ogre-tools/injectable-extension-for-mobx@9.0.0": "@ogre-tools/injectable-extension-for-mobx@9.0.1":
version "9.0.0" version "9.0.1"
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-mobx/-/injectable-extension-for-mobx-9.0.0.tgz#ed14df39b266e521272977821d3e05bcbd647577" resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-extension-for-mobx/-/injectable-extension-for-mobx-9.0.1.tgz#3d9e6e119b7db5a4e4309e89ba6b301635c8da90"
integrity sha512-9Hrtr7AdibcD+Fqn2qNsjiOUakAACO55TB1IqNsOJMMuqQHVB5SFZTHBzdVRqqqY2MwQvWYvd4xfy+beItD/xw== integrity sha512-wNHIG73NTGfmRb0b2nNhJD9ek4RcyBp/189KfrXhTt6/5KwMEuOeJjAbh8xwbhpYJnWFcMzWKLTqePozc+Ntww==
dependencies: dependencies:
"@ogre-tools/fp" "^9.0.0" "@ogre-tools/fp" "^9.0.1"
"@ogre-tools/injectable" "^9.0.0" "@ogre-tools/injectable" "^9.0.1"
lodash "^4.17.21" lodash "^4.17.21"
"@ogre-tools/injectable-react@9.0.0": "@ogre-tools/injectable-react@9.0.1":
version "9.0.0" version "9.0.1"
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-react/-/injectable-react-9.0.0.tgz#c5c510e893a5c1d7994d8709f70606967cabdec2" resolved "https://registry.yarnpkg.com/@ogre-tools/injectable-react/-/injectable-react-9.0.1.tgz#d72a155b914873f1a5e35ee167aa14dd7c0e7454"
integrity sha512-vGQrwkcWibRUWFPbu392riBYY4dXK051FxwyMsDYNRqmvaLo8HuumwjzS1DWS7db/P9Li+Kc+Ms670xIZepcpA== integrity sha512-GjkhhONy4hamw5Mx79ZxhL3Pbgnfnf1mrkixDkqlXFzhdPBHDtCYIZu9Y6NjSRLgEwXTrAPYv9lDqREnRbUwLA==
dependencies: dependencies:
"@ogre-tools/fp" "^9.0.0" "@ogre-tools/fp" "^9.0.1"
"@ogre-tools/injectable" "^9.0.0" "@ogre-tools/injectable" "^9.0.1"
lodash "^4.17.21" lodash "^4.17.21"
"@ogre-tools/injectable@9.0.0", "@ogre-tools/injectable@^9.0.0": "@ogre-tools/injectable@9.0.1", "@ogre-tools/injectable@^9.0.1":
version "9.0.0" version "9.0.1"
resolved "https://registry.yarnpkg.com/@ogre-tools/injectable/-/injectable-9.0.0.tgz#0819bc7b5fbae0a467f3250b10b4adb003268067" resolved "https://registry.yarnpkg.com/@ogre-tools/injectable/-/injectable-9.0.1.tgz#611a2dd8468bfe3610f005178837d76071a44a70"
integrity sha512-z9X86Q9AEkkilLu9V33j/aXv/IUoG944AdfN6WX2zZgJqRNjESN9spoOMqdKqib6JmEjCRxpMvaMwHLQSh14fg== integrity sha512-orcERUOeUEP2oBAcr9rKYbik+r/xJEIb5uedPMMqPzPJnNwZ9JA/1rDEJcx1/I9aHgjUQpeFANjYI4eYDcwEYQ==
dependencies: dependencies:
"@ogre-tools/fp" "^9.0.0" "@ogre-tools/fp" "^9.0.1"
lodash "^4.17.21" lodash "^4.17.21"
"@panva/asn1.js@^1.0.0": "@panva/asn1.js@^1.0.0":