From 4303700bb2d5fcc26f6a251c864b3894c6a3d262 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 24 Mar 2021 15:17:56 +0200 Subject: [PATCH 1/6] Fix: highlight sidebar's active section (#2366) * - fix: highlight active sidebar section / link - fix: caching crd definitions to prevent sidebar's scroll jumps - refactored & simplified `Sidebar` and `SidebarItem` Signed-off-by: Roman * responding to comments Signed-off-by: Roman * adding @jsdoc comments to SidebarItem Signed-off-by: Roman --- .../+custom-resources/custom-resources.tsx | 4 +- .../components/layout/sidebar-item.tsx | 56 +++++++------- src/renderer/components/layout/sidebar.tsx | 74 ++++++++++++------- 3 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/renderer/components/+custom-resources/custom-resources.tsx b/src/renderer/components/+custom-resources/custom-resources.tsx index 3224b08fd3..1772694137 100644 --- a/src/renderer/components/+custom-resources/custom-resources.tsx +++ b/src/renderer/components/+custom-resources/custom-resources.tsx @@ -2,7 +2,7 @@ import React from "react"; import { observer } from "mobx-react"; import { Redirect, Route, Switch } from "react-router"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { crdResourcesRoute, crdRoute, crdURL, crdDefinitionsRoute } from "./crd.route"; +import { crdDefinitionsRoute, crdResourcesRoute, crdURL } from "./crd.route"; import { CrdList } from "./crd-list"; import { CrdResources } from "./crd-resources"; @@ -14,7 +14,7 @@ export class CustomResources extends React.Component { title: "Definitions", component: CustomResources, url: crdURL(), - routePath: crdRoute.path.toString(), + routePath: String(crdDefinitionsRoute.path), } ]; } diff --git a/src/renderer/components/layout/sidebar-item.tsx b/src/renderer/components/layout/sidebar-item.tsx index e2eb942db4..da36b43c17 100644 --- a/src/renderer/components/layout/sidebar-item.tsx +++ b/src/renderer/components/layout/sidebar-item.tsx @@ -6,19 +6,27 @@ import { cssNames, prevDefault } from "../../utils"; import { observer } from "mobx-react"; import { NavLink } from "react-router-dom"; import { Icon } from "../icon"; -import { TabLayoutRoute } from "./tab-layout"; import { sidebarStorage } from "./sidebar-storage"; import { isActiveRoute } from "../../navigation"; interface SidebarItemProps { - id: string; // Used to save nav item collapse/expand state in local storage + /** + * Unique id, used in storage and integration tests + */ + id: string; url: string; - text: React.ReactNode | string; className?: string; + text: React.ReactNode; icon?: React.ReactNode; isHidden?: boolean; + /** + * Forces this item to be also show as active or not. + * + * Default: dynamically checks the location against the `url` props to determine if + * this item should be shown as active + */ isActive?: boolean; - subMenus?: TabLayoutRoute[]; + subMenus?: React.ReactNode | React.ComponentType[]; } @observer @@ -26,22 +34,30 @@ export class SidebarItem extends React.Component { static displayName = "SidebarItem"; get id(): string { - return this.props.id; // unique id, used in storage and integration tests + return this.props.id; } - get compact(): boolean { + @computed get compact(): boolean { return Boolean(sidebarStorage.get().compact); } - get expanded(): boolean { + @computed get expanded(): boolean { return Boolean(sidebarStorage.get().expanded[this.id]); } - @computed get isExpandable(): boolean { - const { subMenus, children } = this.props; - const hasContent = subMenus?.length > 0 || children; + @computed get isActive(): boolean { + return this.props.isActive ?? isActiveRoute({ + path: this.props.url, + exact: true, + }); + } - return Boolean(hasContent && !this.compact) /*not available in compact-mode*/; + @computed get isExpandable(): boolean { + if (this.compact) { + return false; // not available currently + } + + return Boolean(this.props.subMenus || this.props.children); } toggleExpand = () => { @@ -51,11 +67,11 @@ export class SidebarItem extends React.Component { }; render() { - const { isHidden, isActive, subMenus = [], icon, text, children, url, className } = this.props; + const { isHidden, icon, text, children, url, className, subMenus } = this.props; if (isHidden) return null; - const { id, compact, expanded, isExpandable, toggleExpand } = this; + const { isActive, id, compact, expanded, isExpandable, toggleExpand } = this; const classNames = cssNames(SidebarItem.displayName, className, { compact, }); @@ -76,19 +92,7 @@ export class SidebarItem extends React.Component { {isExpandable && expanded && (
    - {subMenus.map(({ title, routePath, url = routePath }) => { - const subItemId = `${id}${routePath}`; - - return ( - - ); - })} + {subMenus} {children}
)} diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 7f0ddd818f..522e06674c 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -1,7 +1,8 @@ import "./sidebar.scss"; +import type { TabLayoutRoute } from "./tab-layout"; import React from "react"; -import type { TabLayoutRoute } from "./tab-layout"; +import { computed } from "mobx"; import { observer } from "mobx-react"; import { NavLink } from "react-router-dom"; import { cssNames } from "../../utils"; @@ -22,7 +23,7 @@ import { UserManagement } from "../+user-management"; import { Storage } from "../+storage"; import { Network } from "../+network"; import { crdStore } from "../+custom-resources/crd.store"; -import { CrdList, crdResourcesRoute, crdRoute, crdURL } from "../+custom-resources"; +import { crdRoute, crdURL } from "../+custom-resources"; import { CustomResources } from "../+custom-resources/custom-resources"; import { isActiveRoute } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac"; @@ -44,29 +45,50 @@ export class Sidebar extends React.Component { crdStore.reloadAll(); } - renderCustomResources() { - if (crdStore.isLoading) { + @computed get crdSubMenus(): React.ReactNode { + if (!crdStore.isLoaded && crdStore.isLoading) { return ; } return Object.entries(crdStore.groups).map(([group, crds]) => { - const submenus: TabLayoutRoute[] = crds.map((crd) => { - return { - title: crd.getResourceKind(), - component: CrdList, - url: crd.getResourceUrl(), - routePath: String(crdResourcesRoute.path), - }; + const crdGroupSubMenu: React.ReactNode = crds.map((crd) => { + return ( + + ); }); return ( + ); + }); + } + + renderTreeFromTabRoutes(tabRoutes: TabLayoutRoute[] = []): React.ReactNode { + if (!tabRoutes.length) { + return null; + } + + return tabRoutes.map(({ title, routePath, url = routePath, exact = true }) => { + const subMenuItemId = `tab-route-item-${url}`; + + return ( + ); }); @@ -122,10 +144,10 @@ export class Sidebar extends React.Component { key={id} id={id} url={pageUrl} + isActive={isActive} text={menuItem.title} icon={} - isActive={isActive} - subMenus={tabRoutes} + subMenus={this.renderTreeFromTabRoutes(tabRoutes)} /> ); }); @@ -172,7 +194,7 @@ export class Sidebar extends React.Component { isActive={isActiveRoute(workloadsRoute)} isHidden={Workloads.tabRoutes.length == 0} url={workloadsURL({ query })} - subMenus={Workloads.tabRoutes} + subMenus={this.renderTreeFromTabRoutes(Workloads.tabRoutes)} text="Workloads" icon={} /> @@ -181,7 +203,7 @@ export class Sidebar extends React.Component { isActive={isActiveRoute(configRoute)} isHidden={Config.tabRoutes.length == 0} url={configURL({ query })} - subMenus={Config.tabRoutes} + subMenus={this.renderTreeFromTabRoutes(Config.tabRoutes)} text="Configuration" icon={} /> @@ -190,7 +212,7 @@ export class Sidebar extends React.Component { isActive={isActiveRoute(networkRoute)} isHidden={Network.tabRoutes.length == 0} url={networkURL({ query })} - subMenus={Network.tabRoutes} + subMenus={this.renderTreeFromTabRoutes(Network.tabRoutes)} text="Network" icon={} /> @@ -199,7 +221,7 @@ export class Sidebar extends React.Component { isActive={isActiveRoute(storageRoute)} isHidden={Storage.tabRoutes.length == 0} url={storageURL({ query })} - subMenus={Storage.tabRoutes} + subMenus={this.renderTreeFromTabRoutes(Storage.tabRoutes)} icon={} text="Storage" /> @@ -223,7 +245,7 @@ export class Sidebar extends React.Component { id="apps" isActive={isActiveRoute(appsRoute)} url={appsURL({ query })} - subMenus={Apps.tabRoutes} + subMenus={this.renderTreeFromTabRoutes(Apps.tabRoutes)} icon={} text="Apps" /> @@ -231,20 +253,20 @@ export class Sidebar extends React.Component { id="users" isActive={isActiveRoute(usersManagementRoute)} url={usersManagementURL({ query })} - subMenus={UserManagement.tabRoutes} + subMenus={this.renderTreeFromTabRoutes(UserManagement.tabRoutes)} icon={} text="Access Control" /> } - text="Custom Resources" > - {this.renderCustomResources()} + {this.renderTreeFromTabRoutes(CustomResources.tabRoutes)} + {this.crdSubMenus} {this.renderRegisteredMenus()} From 34712dd51f1176d6327a2dcbb1c7aa4a0fed0f03 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 24 Mar 2021 10:22:35 -0400 Subject: [PATCH 2/6] release v4.2.0-rc.2 (#2378) Signed-off-by: Sebastian Malton --- package.json | 2 +- static/RELEASE_NOTES.md | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 06066d6ade..e346f8c11f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "kontena-lens", "productName": "Lens", "description": "Lens - The Kubernetes IDE", - "version": "4.2.0-rc.1", + "version": "4.2.0-rc.2", "main": "static/build/main.js", "copyright": "© 2021, Mirantis, Inc.", "license": "MIT", diff --git a/static/RELEASE_NOTES.md b/static/RELEASE_NOTES.md index e75ee62f51..7aa58e564c 100644 --- a/static/RELEASE_NOTES.md +++ b/static/RELEASE_NOTES.md @@ -2,7 +2,7 @@ Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights! -## 4.2.0-rc.1 (current version) +## 4.2.0-rc.2 (current version) - Add lens:// protocol handling with a routing mechanism - Add common app routes to the protocol renderer router from the documentation @@ -18,6 +18,8 @@ Here you can find description of changes we've built into each release. While we - Navigation menu in Preferences - Add terminal clear shortcut for macOS - Add the ability to hide metrics from the UI +- Add notification to user to add accessible namespaces when needed +- Change Cluster Settings button to be a menu like cluster icon menu - Fix: Proper sorting resources by age column - Fix: Events sorting with compact=true is broken - Fix: Two charts refer to an arbitrary repository @@ -30,6 +32,7 @@ Here you can find description of changes we've built into each release. While we - Fix: Extension command palette loading - Fix: Closing workspace menu after clicking on iframe - Fix: extension global pages are never able to be visible +- Fix: recreate proxy kubeconfig if it is deleted ## 4.1.4 From 67898152171cd8a9f6f927f12c47aa306105158c Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 24 Mar 2021 19:22:17 +0200 Subject: [PATCH 3/6] Set initial cursor position for the editor to beginning (#2385) Signed-off-by: Roman --- src/renderer/components/ace-editor/ace-editor.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/components/ace-editor/ace-editor.tsx b/src/renderer/components/ace-editor/ace-editor.tsx index 2dceb48bba..180c142ffd 100644 --- a/src/renderer/components/ace-editor/ace-editor.tsx +++ b/src/renderer/components/ace-editor/ace-editor.tsx @@ -32,6 +32,7 @@ const defaultProps: Partial = { useWorker: false, onBlur: noop, onFocus: noop, + cursorPos: { row: 0, column: 0 }, }; @observer From 7a352537100e3543021f65105fc08f71c700d927 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Thu, 25 Mar 2021 12:50:13 +0200 Subject: [PATCH 4/6] Proxy should listen only on loopback device (#2388) Signed-off-by: Jari Kolehmainen --- src/main/lens-proxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 7e1aa98b7e..0bc3528a33 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -28,7 +28,7 @@ export class LensProxy { } listen(port = this.port): this { - this.proxyServer = this.buildCustomProxy().listen(port); + this.proxyServer = this.buildCustomProxy().listen(port, "127.0.0.1"); logger.info(`[LENS-PROXY]: Proxy server has started at ${this.origin}`); return this; From 2c50e7aa1c97e0764f5bdf628b571e36207814b5 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 25 Mar 2021 13:19:58 +0200 Subject: [PATCH 5/6] refactoring: get rid of SidebarItem.props.subMenus in favour of props.children only (#2384) Signed-off-by: Roman --- .../components/layout/sidebar-item.tsx | 30 ++++--- src/renderer/components/layout/sidebar.tsx | 84 ++++++++++--------- 2 files changed, 61 insertions(+), 53 deletions(-) diff --git a/src/renderer/components/layout/sidebar-item.tsx b/src/renderer/components/layout/sidebar-item.tsx index da36b43c17..64956842aa 100644 --- a/src/renderer/components/layout/sidebar-item.tsx +++ b/src/renderer/components/layout/sidebar-item.tsx @@ -26,7 +26,6 @@ interface SidebarItemProps { * this item should be shown as active */ isActive?: boolean; - subMenus?: React.ReactNode | React.ComponentType[]; } @observer @@ -53,11 +52,9 @@ export class SidebarItem extends React.Component { } @computed get isExpandable(): boolean { - if (this.compact) { - return false; // not available currently - } + if (this.compact) return false; // not available in compact-mode currently - return Boolean(this.props.subMenus || this.props.children); + return Boolean(this.props.children); } toggleExpand = () => { @@ -66,8 +63,22 @@ export class SidebarItem extends React.Component { }); }; + renderSubMenu() { + const { isExpandable, expanded, isActive } = this; + + if (!isExpandable || !expanded) { + return; + } + + return ( +
    + {this.props.children} +
+ ); + } + render() { - const { isHidden, icon, text, children, url, className, subMenus } = this.props; + const { isHidden, icon, text, url, className } = this.props; if (isHidden) return null; @@ -90,12 +101,7 @@ export class SidebarItem extends React.Component { material={expanded ? "keyboard_arrow_up" : "keyboard_arrow_down"} />} - {isExpandable && expanded && ( -
    - {subMenus} - {children} -
- )} + {this.renderSubMenu()} ); } diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 522e06674c..531c9db1a0 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -51,25 +51,20 @@ export class Sidebar extends React.Component { } return Object.entries(crdStore.groups).map(([group, crds]) => { - const crdGroupSubMenu: React.ReactNode = crds.map((crd) => { - return ( - - ); - }); + const id = `crd-group:${group}`; + const crdGroupsPageUrl = crdURL({ query: { groups: group } }); return ( - + + {crds.map((crd) => ( + + ))} + ); }); } @@ -147,8 +142,9 @@ export class Sidebar extends React.Component { isActive={isActive} text={menuItem.title} icon={} - subMenus={this.renderTreeFromTabRoutes(tabRoutes)} - /> + > + {this.renderTreeFromTabRoutes(tabRoutes)} + ); }); } @@ -175,88 +171,94 @@ export class Sidebar extends React.Component {
} /> } /> } - /> + > + {this.renderTreeFromTabRoutes(Workloads.tabRoutes)} + } - /> + > + {this.renderTreeFromTabRoutes(Config.tabRoutes)} + } - /> + > + {this.renderTreeFromTabRoutes(Network.tabRoutes)} + } - text="Storage" - /> + > + {this.renderTreeFromTabRoutes(Storage.tabRoutes)} + } - text="Namespaces" /> } - text="Events" /> } - text="Apps" - /> + > + {this.renderTreeFromTabRoutes(Apps.tabRoutes)} + } - text="Access Control" - /> + > + {this.renderTreeFromTabRoutes(UserManagement.tabRoutes)} + Date: Thu, 25 Mar 2021 17:19:45 +0200 Subject: [PATCH 6/6] Add security policy (#2387) * add security policy Signed-off-by: Jari Kolehmainen * tweak Signed-off-by: Jari Kolehmainen --- SECURITY.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..b1a54ec9d0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Reporting a Vulnerability + +Team Lens encourages users who become aware of a security vulnerability in Lens to contact Team Lens with details of the vulnerability. Team Lens has established an email address that should be used for reporting a vulnerability. Please send descriptions of any vulnerabilities found to security@k8slens.dev. Please include details on the software and hardware configuration of your system so that we can duplicate the issue being reported. + +Team Lens hopes that users encountering a new vulnerability will contact us privately as it is in the best interests of our users that Team Lens has an opportunity to investigate and confirm a suspected vulnerability before it becomes public knowledge. + +In the case of vulnerabilities found in third-party software components used in Lens, please also notify Team Lens as described above.