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

Merge branch 'master' into fix/isolate-react-select-emotion-styles

This commit is contained in:
Alex Andreev 2021-03-26 14:00:37 +03:00
commit b989cc41c8
8 changed files with 130 additions and 83 deletions

9
SECURITY.md Normal file
View File

@ -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.

View File

@ -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",

View File

@ -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;

View File

@ -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),
}
];
}

View File

@ -32,6 +32,7 @@ const defaultProps: Partial<Props> = {
useWorker: false,
onBlur: noop,
onFocus: noop,
cursorPos: { row: 0, column: 0 },
};
@observer

View File

@ -6,19 +6,26 @@ 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[];
}
@observer
@ -26,22 +33,28 @@ export class SidebarItem extends React.Component<SidebarItemProps> {
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 in compact-mode currently
return Boolean(this.props.children);
}
toggleExpand = () => {
@ -50,12 +63,26 @@ export class SidebarItem extends React.Component<SidebarItemProps> {
});
};
renderSubMenu() {
const { isExpandable, expanded, isActive } = this;
if (!isExpandable || !expanded) {
return;
}
return (
<ul className={cssNames("sub-menu", { active: isActive })}>
{this.props.children}
</ul>
);
}
render() {
const { isHidden, isActive, subMenus = [], icon, text, children, url, className } = this.props;
const { isHidden, icon, text, url, className } = 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,
});
@ -74,24 +101,7 @@ export class SidebarItem extends React.Component<SidebarItemProps> {
material={expanded ? "keyboard_arrow_up" : "keyboard_arrow_down"}
/>}
</NavLink>
{isExpandable && expanded && (
<ul className={cssNames("sub-menu", { active: isActive })}>
{subMenus.map(({ title, routePath, url = routePath }) => {
const subItemId = `${id}${routePath}`;
return (
<SidebarItem
key={subItemId}
id={subItemId}
url={url}
text={title}
isActive={isActiveRoute({ path: url, exact: true })}
/>
);
})}
{children}
</ul>
)}
{this.renderSubMenu()}
</div>
);
}

View File

@ -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,45 @@ export class Sidebar extends React.Component<Props> {
crdStore.reloadAll();
}
renderCustomResources() {
if (crdStore.isLoading) {
@computed get crdSubMenus(): React.ReactNode {
if (!crdStore.isLoaded && crdStore.isLoading) {
return <Spinner centerHorizontal/>;
}
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 id = `crd-group:${group}`;
const crdGroupsPageUrl = crdURL({ query: { groups: group } });
return (
<SidebarItem key={id} id={id} text={group} url={crdGroupsPageUrl}>
{crds.map((crd) => (
<SidebarItem
key={crd.getResourceApiBase()}
id={`crd-resource:${crd.getResourceApiBase()}`}
url={crd.getResourceUrl()}
text={crd.getResourceTitle()}
/>
))}
</SidebarItem>
);
});
}
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 (
<SidebarItem
key={group}
id={`crd-group:${group}`}
url={crdURL({ query: { groups: group } })}
subMenus={submenus}
text={group}
isActive={false}
key={subMenuItemId}
id={subMenuItemId}
url={url}
text={title}
isActive={isActiveRoute({ path: routePath, exact })}
/>
);
});
@ -122,11 +139,12 @@ export class Sidebar extends React.Component<Props> {
key={id}
id={id}
url={pageUrl}
isActive={isActive}
text={menuItem.title}
icon={<menuItem.components.Icon/>}
isActive={isActive}
subMenus={tabRoutes}
/>
>
{this.renderTreeFromTabRoutes(tabRoutes)}
</SidebarItem>
);
});
}
@ -153,98 +171,104 @@ export class Sidebar extends React.Component<Props> {
<div className={cssNames("sidebar-nav flex column box grow-fixed", { compact })}>
<SidebarItem
id="cluster"
text="Cluster"
isActive={isActiveRoute(clusterRoute)}
isHidden={!isAllowedResource("nodes")}
url={clusterURL()}
text="Cluster"
icon={<Icon svg="kube"/>}
/>
<SidebarItem
id="nodes"
text="Nodes"
isActive={isActiveRoute(nodesRoute)}
isHidden={!isAllowedResource("nodes")}
url={nodesURL()}
text="Nodes"
icon={<Icon svg="nodes"/>}
/>
<SidebarItem
id="workloads"
text="Workloads"
isActive={isActiveRoute(workloadsRoute)}
isHidden={Workloads.tabRoutes.length == 0}
url={workloadsURL({ query })}
subMenus={Workloads.tabRoutes}
text="Workloads"
icon={<Icon svg="workloads"/>}
/>
>
{this.renderTreeFromTabRoutes(Workloads.tabRoutes)}
</SidebarItem>
<SidebarItem
id="config"
text="Configuration"
isActive={isActiveRoute(configRoute)}
isHidden={Config.tabRoutes.length == 0}
url={configURL({ query })}
subMenus={Config.tabRoutes}
text="Configuration"
icon={<Icon material="list"/>}
/>
>
{this.renderTreeFromTabRoutes(Config.tabRoutes)}
</SidebarItem>
<SidebarItem
id="networks"
text="Network"
isActive={isActiveRoute(networkRoute)}
isHidden={Network.tabRoutes.length == 0}
url={networkURL({ query })}
subMenus={Network.tabRoutes}
text="Network"
icon={<Icon material="device_hub"/>}
/>
>
{this.renderTreeFromTabRoutes(Network.tabRoutes)}
</SidebarItem>
<SidebarItem
id="storage"
text="Storage"
isActive={isActiveRoute(storageRoute)}
isHidden={Storage.tabRoutes.length == 0}
url={storageURL({ query })}
subMenus={Storage.tabRoutes}
icon={<Icon svg="storage"/>}
text="Storage"
/>
>
{this.renderTreeFromTabRoutes(Storage.tabRoutes)}
</SidebarItem>
<SidebarItem
id="namespaces"
text="Namespaces"
isActive={isActiveRoute(namespacesRoute)}
isHidden={!isAllowedResource("namespaces")}
url={namespacesURL()}
icon={<Icon material="layers"/>}
text="Namespaces"
/>
<SidebarItem
id="events"
text="Events"
isActive={isActiveRoute(eventRoute)}
isHidden={!isAllowedResource("events")}
url={eventsURL({ query })}
icon={<Icon material="access_time"/>}
text="Events"
/>
<SidebarItem
id="apps"
text="Apps" // helm charts
isActive={isActiveRoute(appsRoute)}
url={appsURL({ query })}
subMenus={Apps.tabRoutes}
icon={<Icon material="apps"/>}
text="Apps"
/>
>
{this.renderTreeFromTabRoutes(Apps.tabRoutes)}
</SidebarItem>
<SidebarItem
id="users"
text="Access Control"
isActive={isActiveRoute(usersManagementRoute)}
url={usersManagementURL({ query })}
subMenus={UserManagement.tabRoutes}
icon={<Icon material="security"/>}
text="Access Control"
/>
>
{this.renderTreeFromTabRoutes(UserManagement.tabRoutes)}
</SidebarItem>
<SidebarItem
id="custom-resources"
text="Custom Resources"
url={crdURL()}
isActive={isActiveRoute(crdRoute)}
isHidden={!isAllowedResource("customresourcedefinitions")}
url={crdURL()}
subMenus={CustomResources.tabRoutes}
icon={<Icon material="extension"/>}
text="Custom Resources"
>
{this.renderCustomResources()}
{this.renderTreeFromTabRoutes(CustomResources.tabRoutes)}
{this.crdSubMenus}
</SidebarItem>
{this.renderRegisteredMenus()}
</div>

View File

@ -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