mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Rework extension API into parts (#2879)
* `Main`, `Common`, and `Renderer` * move registry types to Common.Types Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
db54a658a2
commit
df1f6e128e
28 files changed
+227
-161
No files matched your search
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "kube-object-event-status",
|
||||
"version": "0.1.0",
|
||||
"description": "Adds kube object status from events",
|
||||
"renderer": "dist/renderer.js",
|
||||
"lens": {
|
||||
"metadata": {},
|
||||
"styles": []
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack && npm pack",
|
||||
"dev": "webpack --watch",
|
||||
"test": "echo NO TESTS"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||
"ts-loader": "^8.0.4",
|
||||
"typescript": "^4.0.3",
|
||||
"webpack": "^4.44.2"
|
||||
}
|
||||
}
|
||||
@@ -19,45 +19,45 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { LensRendererExtension, K8sApi } from "@k8slens/extensions";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { resolveStatus, resolveStatusForCronJobs, resolveStatusForPods } from "./src/resolver";
|
||||
|
||||
export default class EventResourceStatusRendererExtension extends LensRendererExtension {
|
||||
export default class EventResourceStatusRendererExtension extends Renderer.LensExtension {
|
||||
kubeObjectStatusTexts = [
|
||||
{
|
||||
kind: "Pod",
|
||||
apiVersions: ["v1"],
|
||||
resolve: (pod: K8sApi.Pod) => resolveStatusForPods(pod)
|
||||
resolve: (pod: Renderer.K8sApi.Pod) => resolveStatusForPods(pod)
|
||||
},
|
||||
{
|
||||
kind: "ReplicaSet",
|
||||
apiVersions: ["v1"],
|
||||
resolve: (replicaSet: K8sApi.ReplicaSet) => resolveStatus(replicaSet)
|
||||
resolve: (replicaSet: Renderer.K8sApi.ReplicaSet) => resolveStatus(replicaSet)
|
||||
},
|
||||
{
|
||||
kind: "Deployment",
|
||||
apiVersions: ["apps/v1"],
|
||||
resolve: (deployment: K8sApi.Deployment) => resolveStatus(deployment)
|
||||
resolve: (deployment: Renderer.K8sApi.Deployment) => resolveStatus(deployment)
|
||||
},
|
||||
{
|
||||
kind: "StatefulSet",
|
||||
apiVersions: ["apps/v1"],
|
||||
resolve: (statefulSet: K8sApi.StatefulSet) => resolveStatus(statefulSet)
|
||||
resolve: (statefulSet: Renderer.K8sApi.StatefulSet) => resolveStatus(statefulSet)
|
||||
},
|
||||
{
|
||||
kind: "DaemonSet",
|
||||
apiVersions: ["apps/v1"],
|
||||
resolve: (daemonSet: K8sApi.DaemonSet) => resolveStatus(daemonSet)
|
||||
resolve: (daemonSet: Renderer.K8sApi.DaemonSet) => resolveStatus(daemonSet)
|
||||
},
|
||||
{
|
||||
kind: "Job",
|
||||
apiVersions: ["batch/v1"],
|
||||
resolve: (job: K8sApi.Job) => resolveStatus(job)
|
||||
resolve: (job: Renderer.K8sApi.Job) => resolveStatus(job)
|
||||
},
|
||||
{
|
||||
kind: "CronJob",
|
||||
apiVersions: ["batch/v1"],
|
||||
resolve: (cronJob: K8sApi.CronJob) => resolveStatusForCronJobs(cronJob)
|
||||
resolve: (cronJob: Renderer.K8sApi.CronJob) => resolveStatusForCronJobs(cronJob)
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -19,11 +19,19 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { K8sApi } from "@k8slens/extensions";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
|
||||
export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatus {
|
||||
const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi);
|
||||
const events = (eventStore as K8sApi.EventStore).getEventsByObject(object);
|
||||
const { apiManager, eventApi, KubeObjectStatusLevel } = Renderer.K8sApi;
|
||||
|
||||
type KubeObject = Renderer.K8sApi.KubeObject;
|
||||
type Pod = Renderer.K8sApi.Pod;
|
||||
type CronJob = Renderer.K8sApi.CronJob;
|
||||
type KubeObjectStatus = Renderer.K8sApi.KubeObjectStatus;
|
||||
type EventStore = Renderer.K8sApi.EventStore;
|
||||
|
||||
export function resolveStatus(object: KubeObject): KubeObjectStatus {
|
||||
const eventStore = apiManager.getStore(eventApi);
|
||||
const events = (eventStore as EventStore).getEventsByObject(object);
|
||||
const warnings = events.filter(evt => evt.isWarning());
|
||||
|
||||
if (!events.length || !warnings.length) {
|
||||
@@ -32,18 +40,18 @@ export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatu
|
||||
const event = [...warnings, ...events][0]; // get latest event
|
||||
|
||||
return {
|
||||
level: K8sApi.KubeObjectStatusLevel.WARNING,
|
||||
level: KubeObjectStatusLevel.WARNING,
|
||||
text: `${event.message}`,
|
||||
timestamp: event.metadata.creationTimestamp
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus {
|
||||
export function resolveStatusForPods(pod: Pod): KubeObjectStatus {
|
||||
if (!pod.hasIssues()) {
|
||||
return null;
|
||||
}
|
||||
const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi);
|
||||
const events = (eventStore as K8sApi.EventStore).getEventsByObject(pod);
|
||||
const eventStore = apiManager.getStore(eventApi);
|
||||
const events = (eventStore as EventStore).getEventsByObject(pod);
|
||||
const warnings = events.filter(evt => evt.isWarning());
|
||||
|
||||
if (!events.length || !warnings.length) {
|
||||
@@ -52,15 +60,15 @@ export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus {
|
||||
const event = [...warnings, ...events][0]; // get latest event
|
||||
|
||||
return {
|
||||
level: K8sApi.KubeObjectStatusLevel.WARNING,
|
||||
level: KubeObjectStatusLevel.WARNING,
|
||||
text: `${event.message}`,
|
||||
timestamp: event.metadata.creationTimestamp
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeObjectStatus {
|
||||
const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi);
|
||||
let events = (eventStore as K8sApi.EventStore).getEventsByObject(cronJob);
|
||||
export function resolveStatusForCronJobs(cronJob: CronJob): KubeObjectStatus {
|
||||
const eventStore = apiManager.getStore(eventApi);
|
||||
let events = (eventStore as EventStore).getEventsByObject(cronJob);
|
||||
const warnings = events.filter(evt => evt.isWarning());
|
||||
|
||||
if (cronJob.isNeverRun()) {
|
||||
@@ -73,7 +81,7 @@ export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeOb
|
||||
const event = [...warnings, ...events][0]; // get latest event
|
||||
|
||||
return {
|
||||
level: K8sApi.KubeObjectStatusLevel.WARNING,
|
||||
level: KubeObjectStatusLevel.WARNING,
|
||||
text: `${event.message}`,
|
||||
timestamp: event.metadata.creationTimestamp
|
||||
};
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { LensRendererExtension, Catalog } from "@k8slens/extensions";
|
||||
import { Common, Renderer } from "@k8slens/extensions";
|
||||
import { MetricsSettings } from "./src/metrics-settings";
|
||||
|
||||
export default class ClusterMetricsFeatureExtension extends LensRendererExtension {
|
||||
export default class ClusterMetricsFeatureExtension extends Renderer.LensExtension {
|
||||
entitySettings = [
|
||||
{
|
||||
apiVersions: ["entity.k8slens.dev/v1alpha1"],
|
||||
@@ -31,7 +31,7 @@ export default class ClusterMetricsFeatureExtension extends LensRendererExtensio
|
||||
title: "Lens Metrics",
|
||||
priority: 5,
|
||||
components: {
|
||||
View: ({ entity = null }: { entity: Catalog.KubernetesCluster}) => {
|
||||
View: ({ entity = null }: { entity: Common.Catalog.KubernetesCluster}) => {
|
||||
return (
|
||||
<MetricsSettings cluster={entity} />
|
||||
);
|
||||
|
||||
@@ -19,10 +19,14 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Catalog, K8sApi } from "@k8slens/extensions";
|
||||
import { Renderer, Common } from "@k8slens/extensions";
|
||||
import semver from "semver";
|
||||
import * as path from "path";
|
||||
|
||||
const { ResourceStack, forCluster, StorageClass, Namespace } = Renderer.K8sApi;
|
||||
|
||||
type ResourceStack = Renderer.K8sApi.ResourceStack;
|
||||
|
||||
export interface MetricsConfiguration {
|
||||
// Placeholder for Metrics config structure
|
||||
prometheus: {
|
||||
@@ -58,10 +62,10 @@ export class MetricsFeature {
|
||||
name = "lens-metrics";
|
||||
latestVersion = "v2.26.0-lens1";
|
||||
|
||||
protected stack: K8sApi.ResourceStack;
|
||||
protected stack: ResourceStack;
|
||||
|
||||
constructor(protected cluster: Catalog.KubernetesCluster) {
|
||||
this.stack = new K8sApi.ResourceStack(cluster, this.name);
|
||||
constructor(protected cluster: Common.Catalog.KubernetesCluster) {
|
||||
this.stack = new ResourceStack(cluster, this.name);
|
||||
}
|
||||
|
||||
get resourceFolder() {
|
||||
@@ -70,7 +74,7 @@ export class MetricsFeature {
|
||||
|
||||
async install(config: MetricsConfiguration): Promise<string> {
|
||||
// Check if there are storageclasses
|
||||
const storageClassApi = K8sApi.forCluster(this.cluster, K8sApi.StorageClass);
|
||||
const storageClassApi = forCluster(this.cluster, StorageClass);
|
||||
const scs = await storageClassApi.list();
|
||||
|
||||
config.persistence.enabled = scs.some(sc => (
|
||||
@@ -91,7 +95,7 @@ export class MetricsFeature {
|
||||
const status: MetricsStatus = { installed: false, canUpgrade: false};
|
||||
|
||||
try {
|
||||
const namespaceApi = K8sApi.forCluster(this.cluster, K8sApi.Namespace);
|
||||
const namespaceApi = forCluster(this.cluster, Namespace);
|
||||
const namespace = await namespaceApi.get({name: "lens-metrics"});
|
||||
|
||||
if (namespace?.kind) {
|
||||
|
||||
@@ -19,13 +19,22 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import React from "react";
|
||||
import { Component, Catalog, K8sApi } from "@k8slens/extensions";
|
||||
import { Common, Renderer } from "@k8slens/extensions";
|
||||
import { observer } from "mobx-react";
|
||||
import { computed, observable, makeObservable } from "mobx";
|
||||
import { MetricsFeature, MetricsConfiguration } from "./metrics-feature";
|
||||
|
||||
const {
|
||||
K8sApi: {
|
||||
forCluster, StatefulSet, DaemonSet, Deployment,
|
||||
},
|
||||
Component: {
|
||||
SubTitle, FormSwitch, Switcher, Button,
|
||||
}
|
||||
} = Renderer;
|
||||
|
||||
interface Props {
|
||||
cluster: Catalog.KubernetesCluster;
|
||||
cluster: Common.Catalog.KubernetesCluster;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -102,7 +111,7 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
this.changed = true;
|
||||
}
|
||||
|
||||
const statefulSet = K8sApi.forCluster(this.props.cluster, K8sApi.StatefulSet);
|
||||
const statefulSet = forCluster(this.props.cluster, StatefulSet);
|
||||
|
||||
try {
|
||||
await statefulSet.get({name: "prometheus", namespace: "lens-metrics"});
|
||||
@@ -115,7 +124,7 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const deployment = K8sApi.forCluster(this.props.cluster, K8sApi.Deployment);
|
||||
const deployment = forCluster(this.props.cluster, Deployment);
|
||||
|
||||
try {
|
||||
await deployment.get({name: "kube-state-metrics", namespace: "lens-metrics"});
|
||||
@@ -128,7 +137,7 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const daemonSet = K8sApi.forCluster(this.props.cluster, K8sApi.DaemonSet);
|
||||
const daemonSet = forCluster(this.props.cluster, DaemonSet);
|
||||
|
||||
try {
|
||||
await daemonSet.get({name: "node-exporter", namespace: "lens-metrics"});
|
||||
@@ -211,10 +220,10 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
</section>
|
||||
)}
|
||||
<section>
|
||||
<Component.SubTitle title="Prometheus" />
|
||||
<Component.FormSwitch
|
||||
<SubTitle title="Prometheus" />
|
||||
<FormSwitch
|
||||
control={
|
||||
<Component.Switcher
|
||||
<Switcher
|
||||
disabled={this.featureStates.kubeStateMetrics === undefined || !this.isTogglable}
|
||||
checked={!!this.featureStates.prometheus && this.props.cluster.status.active}
|
||||
onChange={v => this.togglePrometheus(v.target.checked)}
|
||||
@@ -229,10 +238,10 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Component.SubTitle title="Kube State Metrics" />
|
||||
<Component.FormSwitch
|
||||
<SubTitle title="Kube State Metrics" />
|
||||
<FormSwitch
|
||||
control={
|
||||
<Component.Switcher
|
||||
<Switcher
|
||||
disabled={this.featureStates.kubeStateMetrics === undefined || !this.isTogglable}
|
||||
checked={!!this.featureStates.kubeStateMetrics && this.props.cluster.status.active}
|
||||
onChange={v => this.toggleKubeStateMetrics(v.target.checked)}
|
||||
@@ -248,10 +257,10 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Component.SubTitle title="Node Exporter" />
|
||||
<Component.FormSwitch
|
||||
<SubTitle title="Node Exporter" />
|
||||
<FormSwitch
|
||||
control={
|
||||
<Component.Switcher
|
||||
<Switcher
|
||||
disabled={this.featureStates.nodeExporter === undefined || !this.isTogglable}
|
||||
checked={!!this.featureStates.nodeExporter && this.props.cluster.status.active}
|
||||
onChange={v => this.toggleNodeExporter(v.target.checked)}
|
||||
@@ -267,7 +276,7 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Component.Button
|
||||
<Button
|
||||
label={this.buttonLabel}
|
||||
waiting={this.inProgress}
|
||||
onClick={() => this.save()}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { LensRendererExtension } from "@k8slens/extensions";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import React from "react";
|
||||
import { NodeMenu, NodeMenuProps } from "./src/node-menu";
|
||||
|
||||
export default class NodeMenuRendererExtension extends LensRendererExtension {
|
||||
export default class NodeMenuRendererExtension extends Renderer.LensExtension {
|
||||
kubeObjectMenuItems = [
|
||||
{
|
||||
kind: "Node",
|
||||
|
||||
@@ -20,9 +20,23 @@
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Component, K8sApi, Navigation} from "@k8slens/extensions";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
|
||||
export interface NodeMenuProps extends Component.KubeObjectMenuProps<K8sApi.Node> {
|
||||
type Node = Renderer.K8sApi.Node;
|
||||
|
||||
const {
|
||||
Component: {
|
||||
terminalStore,
|
||||
createTerminalTab,
|
||||
ConfirmDialog,
|
||||
MenuItem,
|
||||
Icon,
|
||||
},
|
||||
Navigation
|
||||
} = Renderer;
|
||||
|
||||
|
||||
export interface NodeMenuProps extends Renderer.Component.KubeObjectMenuProps<Node> {
|
||||
}
|
||||
|
||||
export function NodeMenu(props: NodeMenuProps) {
|
||||
@@ -32,7 +46,7 @@ export function NodeMenu(props: NodeMenuProps) {
|
||||
const nodeName = node.getName();
|
||||
|
||||
const sendToTerminal = (command: string) => {
|
||||
Component.terminalStore.sendCommand(command, {
|
||||
terminalStore.sendCommand(command, {
|
||||
enter: true,
|
||||
newTab: true,
|
||||
});
|
||||
@@ -40,7 +54,7 @@ export function NodeMenu(props: NodeMenuProps) {
|
||||
};
|
||||
|
||||
const shell = () => {
|
||||
Component.createTerminalTab({
|
||||
createTerminalTab({
|
||||
title: `Node: ${nodeName}`,
|
||||
node: nodeName,
|
||||
});
|
||||
@@ -58,7 +72,7 @@ export function NodeMenu(props: NodeMenuProps) {
|
||||
const drain = () => {
|
||||
const command = `kubectl drain ${nodeName} --delete-local-data --ignore-daemonsets --force`;
|
||||
|
||||
Component.ConfirmDialog.open({
|
||||
ConfirmDialog.open({
|
||||
ok: () => sendToTerminal(command),
|
||||
labelOk: `Drain Node`,
|
||||
message: (
|
||||
@@ -71,26 +85,26 @@ export function NodeMenu(props: NodeMenuProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Component.MenuItem onClick={shell}>
|
||||
<Component.Icon svg="ssh" interactive={toolbar} title="Node shell"/>
|
||||
<MenuItem onClick={shell}>
|
||||
<Icon svg="ssh" interactive={toolbar} title="Node shell"/>
|
||||
<span className="title">Shell</span>
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
{!node.isUnschedulable() && (
|
||||
<Component.MenuItem onClick={cordon}>
|
||||
<Component.Icon material="pause_circle_filled" title="Cordon" interactive={toolbar}/>
|
||||
<MenuItem onClick={cordon}>
|
||||
<Icon material="pause_circle_filled" title="Cordon" interactive={toolbar}/>
|
||||
<span className="title">Cordon</span>
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
)}
|
||||
{node.isUnschedulable() && (
|
||||
<Component.MenuItem onClick={unCordon}>
|
||||
<Component.Icon material="play_circle_filled" title="Uncordon" interactive={toolbar}/>
|
||||
<MenuItem onClick={unCordon}>
|
||||
<Icon material="play_circle_filled" title="Uncordon" interactive={toolbar}/>
|
||||
<span className="title">Uncordon</span>
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
)}
|
||||
<Component.MenuItem onClick={drain}>
|
||||
<Component.Icon material="delete_sweep" title="Drain" interactive={toolbar}/>
|
||||
<MenuItem onClick={drain}>
|
||||
<Icon material="delete_sweep" title="Drain" interactive={toolbar}/>
|
||||
<span className="title">Drain</span>
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -19,12 +19,12 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { LensRendererExtension } from "@k8slens/extensions";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { PodShellMenu, PodShellMenuProps } from "./src/shell-menu";
|
||||
import { PodLogsMenu, PodLogsMenuProps } from "./src/logs-menu";
|
||||
import React from "react";
|
||||
|
||||
export default class PodMenuRendererExtension extends LensRendererExtension {
|
||||
export default class PodMenuRendererExtension extends Renderer.LensExtension {
|
||||
kubeObjectMenuItems = [
|
||||
{
|
||||
kind: "Pod",
|
||||
|
||||
@@ -20,17 +20,34 @@
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Component, K8sApi, Util, Navigation } from "@k8slens/extensions";
|
||||
import { Renderer, Common } from "@k8slens/extensions";
|
||||
|
||||
export interface PodLogsMenuProps extends Component.KubeObjectMenuProps<K8sApi.Pod> {
|
||||
type Pod = Renderer.K8sApi.Pod;
|
||||
type IPodContainer = Renderer.K8sApi.IPodContainer;
|
||||
|
||||
const {
|
||||
Component: {
|
||||
logTabStore,
|
||||
MenuItem,
|
||||
Icon,
|
||||
SubMenu,
|
||||
StatusBrick,
|
||||
},
|
||||
Navigation,
|
||||
} = Renderer;
|
||||
const {
|
||||
Util,
|
||||
} = Common;
|
||||
|
||||
export interface PodLogsMenuProps extends Renderer.Component.KubeObjectMenuProps<Pod> {
|
||||
}
|
||||
|
||||
export class PodLogsMenu extends React.Component<PodLogsMenuProps> {
|
||||
showLogs(container: K8sApi.IPodContainer) {
|
||||
showLogs(container: IPodContainer) {
|
||||
Navigation.hideDetails();
|
||||
const pod = this.props.object;
|
||||
|
||||
Component.logTabStore.createPodTab({
|
||||
logTabStore.createPodTab({
|
||||
selectedPod: pod,
|
||||
selectedContainer: container,
|
||||
});
|
||||
@@ -44,35 +61,35 @@ export class PodLogsMenu extends React.Component<PodLogsMenuProps> {
|
||||
if (!containers.length) return null;
|
||||
|
||||
return (
|
||||
<Component.MenuItem onClick={Util.prevDefault(() => this.showLogs(containers[0]))}>
|
||||
<Component.Icon material="subject" title="Logs" interactive={toolbar}/>
|
||||
<MenuItem onClick={Util.prevDefault(() => this.showLogs(containers[0]))}>
|
||||
<Icon material="subject" title="Logs" interactive={toolbar}/>
|
||||
<span className="title">Logs</span>
|
||||
{containers.length > 1 && (
|
||||
<>
|
||||
<Component.Icon className="arrow" material="keyboard_arrow_right"/>
|
||||
<Component.SubMenu>
|
||||
<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 ? (
|
||||
<Component.StatusBrick
|
||||
<StatusBrick
|
||||
className={Util.cssNames(Object.keys(status.state)[0], { ready: status.ready })}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<Component.MenuItem key={name} onClick={Util.prevDefault(() => this.showLogs(container))} className="flex align-center">
|
||||
<MenuItem key={name} onClick={Util.prevDefault(() => this.showLogs(container))} className="flex align-center">
|
||||
{brick}
|
||||
<span>{name}</span>
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
);
|
||||
})
|
||||
}
|
||||
</Component.SubMenu>
|
||||
</SubMenu>
|
||||
</>
|
||||
)}
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,26 @@
|
||||
|
||||
|
||||
import React from "react";
|
||||
import { Component, K8sApi, Util, Navigation } from "@k8slens/extensions";
|
||||
import { Renderer, Common } from "@k8slens/extensions";
|
||||
|
||||
export interface PodShellMenuProps extends Component.KubeObjectMenuProps<K8sApi.Pod> {
|
||||
type Pod = Renderer.K8sApi.Pod;
|
||||
|
||||
const {
|
||||
Component: {
|
||||
createTerminalTab,
|
||||
terminalStore,
|
||||
MenuItem,
|
||||
Icon,
|
||||
SubMenu,
|
||||
StatusBrick,
|
||||
},
|
||||
Navigation,
|
||||
} = Renderer;
|
||||
const {
|
||||
Util,
|
||||
} = Common;
|
||||
|
||||
export interface PodShellMenuProps extends Renderer.Component.KubeObjectMenuProps<Pod> {
|
||||
}
|
||||
|
||||
export class PodShellMenu extends React.Component<PodShellMenuProps> {
|
||||
@@ -44,11 +61,11 @@ export class PodShellMenu extends React.Component<PodShellMenuProps> {
|
||||
command = `${command} sh -c "clear; (bash || ash || sh)"`;
|
||||
}
|
||||
|
||||
const shell = Component.createTerminalTab({
|
||||
const shell = createTerminalTab({
|
||||
title: `Pod: ${pod.getName()} (namespace: ${pod.getNs()})`
|
||||
});
|
||||
|
||||
Component.terminalStore.sendCommand(command, {
|
||||
terminalStore.sendCommand(command, {
|
||||
enter: true,
|
||||
tabId: shell.id
|
||||
});
|
||||
@@ -61,29 +78,29 @@ export class PodShellMenu extends React.Component<PodShellMenuProps> {
|
||||
if (!containers.length) return null;
|
||||
|
||||
return (
|
||||
<Component.MenuItem onClick={Util.prevDefault(() => this.execShell(containers[0].name))}>
|
||||
<Component.Icon svg="ssh" interactive={toolbar} title="Pod shell"/>
|
||||
<MenuItem onClick={Util.prevDefault(() => this.execShell(containers[0].name))}>
|
||||
<Icon svg="ssh" interactive={toolbar} title="Pod shell"/>
|
||||
<span className="title">Shell</span>
|
||||
{containers.length > 1 && (
|
||||
<>
|
||||
<Component.Icon className="arrow" material="keyboard_arrow_right"/>
|
||||
<Component.SubMenu>
|
||||
<Icon className="arrow" material="keyboard_arrow_right"/>
|
||||
<SubMenu>
|
||||
{
|
||||
containers.map(container => {
|
||||
const { name } = container;
|
||||
|
||||
return (
|
||||
<Component.MenuItem key={name} onClick={Util.prevDefault(() => this.execShell(name))} className="flex align-center">
|
||||
<Component.StatusBrick/>
|
||||
<MenuItem key={name} onClick={Util.prevDefault(() => this.execShell(name))} className="flex align-center">
|
||||
<StatusBrick/>
|
||||
<span>{name}</span>
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
);
|
||||
})
|
||||
}
|
||||
</Component.SubMenu>
|
||||
</SubMenu>
|
||||
</>
|
||||
)}
|
||||
</Component.MenuItem>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user