Allow extensions to register kube-object menus + details (#1108)

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen authored and GitHub committed 2020-10-22 21:41:20 +03:00
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,
})