mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Allow extensions to register kube-object menus + details (#1108)
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
91bef77997
commit
99db7aca19
101 files changed
+7858
-1604
No files matched your search
@@ -6,7 +6,7 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { autorun, observable, reaction, toJS } from "mobx";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { IPodMetrics, nodesApi, Pod, podsApi, pvcApi, configMapApi } from "../../api/endpoints";
|
||||
import { IPodMetrics, nodesApi, Pod, pvcApi, configMapApi } from "../../api/endpoints";
|
||||
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||
import { Badge } from "../badge";
|
||||
import { autobind, cssNames, interval } from "../../utils";
|
||||
@@ -22,9 +22,8 @@ import { getDetailsUrl } from "../../navigation";
|
||||
import { KubeObjectDetailsProps } from "../kube-object";
|
||||
import { getItemMetrics } from "../../api/endpoints/metrics.api";
|
||||
import { PodCharts, podMetricTabs } from "./pod-charts";
|
||||
import { lookupApiLink } from "../../api/kube-api";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<Pod> {
|
||||
}
|
||||
@@ -223,6 +222,10 @@ export class PodDetails extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
apiManager.registerViews(podsApi, {
|
||||
Details: PodDetails
|
||||
kubeObjectDetailRegistry.add({
|
||||
kind: "Pod",
|
||||
apiVersions: ["v1"],
|
||||
components: {
|
||||
Details: (props: any) => <PodDetails {...props} />
|
||||
}
|
||||
})
|
||||
@@ -1,10 +0,0 @@
|
||||
.PodMenu {
|
||||
.StatusBrick {
|
||||
margin-right: $margin;
|
||||
@include pod-status-bgs;
|
||||
|
||||
&.running:not(.ready) {
|
||||
background-color: $pod-status-pending-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
import "./pod-menu.scss";
|
||||
|
||||
import React from "react";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { MenuItem, SubMenu } from "../menu";
|
||||
import { IPodContainer, Pod } from "../../api/endpoints";
|
||||
import { Icon } from "../icon";
|
||||
import { StatusBrick } from "../status-brick";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { cssNames, prevDefault } from "../../utils";
|
||||
import { terminalStore, createTerminalTab } from "../dock/terminal.store";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { hideDetails } from "../../navigation";
|
||||
import { createPodLogsTab } from "../dock/pod-logs.store";
|
||||
|
||||
interface Props extends KubeObjectMenuProps<Pod> {
|
||||
}
|
||||
|
||||
export class PodMenu extends React.Component<Props> {
|
||||
async execShell(container?: string) {
|
||||
hideDetails();
|
||||
const { object: pod } = this.props
|
||||
const containerParam = container ? `-c ${container}` : ""
|
||||
let command = `kubectl exec -i -t -n ${pod.getNs()} ${pod.getName()} ${containerParam} "--"`
|
||||
if (window.navigator.platform !== "Win32") {
|
||||
command = `exec ${command}`
|
||||
}
|
||||
if (pod.getSelectedNodeOs() === "windows") {
|
||||
command = `${command} powershell`
|
||||
} else {
|
||||
command = `${command} sh -c "clear; (bash || ash || sh)"`
|
||||
}
|
||||
|
||||
const shell = createTerminalTab({
|
||||
title: _i18n._(t`Pod`) + `: ${pod.getName()} (namespace: ${pod.getNs()})`
|
||||
});
|
||||
|
||||
terminalStore.sendCommand(command, {
|
||||
enter: true,
|
||||
tabId: shell.id
|
||||
});
|
||||
}
|
||||
|
||||
showLogs(container: IPodContainer) {
|
||||
hideDetails();
|
||||
const pod = this.props.object;
|
||||
createPodLogsTab({
|
||||
pod,
|
||||
containers: pod.getContainers(),
|
||||
initContainers: pod.getInitContainers(),
|
||||
selectedContainer: container,
|
||||
showTimestamps: false,
|
||||
previous: false,
|
||||
tailLines: 1000
|
||||
});
|
||||
}
|
||||
|
||||
renderShellMenu() {
|
||||
const { object: pod, toolbar } = this.props
|
||||
const containers = pod.getRunningContainers();
|
||||
if (!containers.length) return;
|
||||
return (
|
||||
<MenuItem onClick={prevDefault(() => this.execShell(containers[0].name))}>
|
||||
<Icon svg="ssh" interactive={toolbar} title={_i18n._(t`Pod shell`)}/>
|
||||
<span className="title"><Trans>Shell</Trans></span>
|
||||
{containers.length > 1 && (
|
||||
<>
|
||||
<Icon className="arrow" material="keyboard_arrow_right"/>
|
||||
<SubMenu>
|
||||
{
|
||||
containers.map(container => {
|
||||
const { name } = container;
|
||||
return (
|
||||
<MenuItem key={name} onClick={prevDefault(() => this.execShell(name))} className="flex align-center">
|
||||
<StatusBrick/>
|
||||
{name}
|
||||
</MenuItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
</SubMenu>
|
||||
</>
|
||||
)}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
renderLogsMenu() {
|
||||
const { object: pod, toolbar } = this.props
|
||||
const containers = pod.getAllContainers();
|
||||
const statuses = pod.getContainerStatuses();
|
||||
if (!containers.length) return;
|
||||
return (
|
||||
<MenuItem onClick={prevDefault(() => this.showLogs(containers[0]))}>
|
||||
<Icon material="subject" title={_i18n._(t`Logs`)} interactive={toolbar}/>
|
||||
<span className="title"><Trans>Logs</Trans></span>
|
||||
{containers.length > 1 && (
|
||||
<>
|
||||
<Icon className="arrow" material="keyboard_arrow_right"/>
|
||||
<SubMenu>
|
||||
{
|
||||
containers.map(container => {
|
||||
const { name } = container
|
||||
const status = statuses.find(status => status.name === name);
|
||||
const brick = status ? (
|
||||
<StatusBrick
|
||||
className={cssNames(Object.keys(status.state)[0], { ready: status.ready })}
|
||||
/>
|
||||
) : null
|
||||
return (
|
||||
<MenuItem key={name} onClick={prevDefault(() => this.showLogs(container))} className="flex align-center">
|
||||
{brick}
|
||||
{name}
|
||||
</MenuItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
</SubMenu>
|
||||
</>
|
||||
)}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { ...menuProps } = this.props;
|
||||
return (
|
||||
<KubeObjectMenu {...menuProps} className="PodMenu">
|
||||
{this.renderShellMenu()}
|
||||
{this.renderLogsMenu()}
|
||||
</KubeObjectMenu>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,7 @@ import { volumeClaimStore } from "../+storage-volume-claims/volume-claim.store";
|
||||
import { IPodsRouteParams } from "../+workloads";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import { Pod, podsApi } from "../../api/endpoints";
|
||||
import { PodMenu } from "./pod-menu";
|
||||
import { Pod } from "../../api/endpoints";
|
||||
import { StatusBrick } from "../status-brick";
|
||||
import { cssNames, stopPropagation } from "../../utils";
|
||||
import { KubeEventIcon } from "../+events/kube-event-icon";
|
||||
@@ -20,7 +19,6 @@ import toPairs from "lodash/toPairs";
|
||||
import startCase from "lodash/startCase";
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import { lookupApiLink } from "../../api/kube-api";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
|
||||
enum sortBy {
|
||||
name = "name",
|
||||
@@ -119,14 +117,7 @@ export class Pods extends React.Component<Props> {
|
||||
pod.getAge(),
|
||||
{ title: pod.getStatusMessage(), className: kebabCase(pod.getStatusMessage()) }
|
||||
]}
|
||||
renderItemMenu={(item: Pod) => {
|
||||
return <PodMenu object={item}/>
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
apiManager.registerViews(podsApi, {
|
||||
Menu: PodMenu,
|
||||
})
|
||||
Reference in new issue
Block a user