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:
parent
db54a658a2
commit
df1f6e128e
25
extensions/kube-object-event-status/package/package.json
Normal file
25
extensions/kube-object-event-status/package/package.json
Normal file
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import { catalogEntityRegistry as registry } from "../../main/catalog";
|
||||
|
||||
export { catalogCategoryRegistry as catalogCategories } from "../../common/catalog/catalog-category-registry";
|
||||
export * from "../../common/catalog-entities";
|
||||
export * from "../../common/catalog/catalog-entity";
|
||||
|
||||
export class CatalogEntityRegistry {
|
||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||
@ -19,27 +19,19 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Lens-extensions api developer's kit
|
||||
export { LensMainExtension } from "../lens-main-extension";
|
||||
export { LensRendererExtension } from "../lens-renderer-extension";
|
||||
|
||||
// APIs
|
||||
import * as App from "./app";
|
||||
import * as EventBus from "./event-bus";
|
||||
import * as Store from "./stores";
|
||||
import * as Util from "./utils";
|
||||
import * as Interface from "../interfaces";
|
||||
import * as Catalog from "./catalog";
|
||||
import * as Types from "./types";
|
||||
import * as Ipc from "./ipc";
|
||||
|
||||
export {
|
||||
App,
|
||||
EventBus,
|
||||
Catalog,
|
||||
Interface,
|
||||
Store,
|
||||
Types,
|
||||
Util,
|
||||
Ipc,
|
||||
};
|
||||
@ -22,3 +22,5 @@
|
||||
export type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent;
|
||||
export type IpcRendererEvent = Electron.IpcRendererEvent;
|
||||
export type IpcMainEvent = Electron.IpcMainEvent;
|
||||
|
||||
export * from "./registrations";
|
||||
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export { IpcMain as Main } from "../ipc/ipc-main";
|
||||
export { IpcRegistrar as Registrar } from "../ipc/ipc-registrar";
|
||||
@ -22,5 +22,12 @@
|
||||
// Extensions-api types bundle (main + renderer)
|
||||
// Available for lens-extensions via NPM-package "@k8slens/extensions"
|
||||
|
||||
export * from "./core-api";
|
||||
export * from "./renderer-api";
|
||||
import * as Common from "./common-api";
|
||||
import * as Renderer from "./renderer-api";
|
||||
import * as Main from "./main-api";
|
||||
|
||||
export {
|
||||
Common,
|
||||
Renderer,
|
||||
Main,
|
||||
};
|
||||
|
||||
@ -337,7 +337,11 @@ export class ExtensionLoader extends Singleton {
|
||||
try {
|
||||
return __non_webpack_require__(extAbsolutePath).default;
|
||||
} catch (error) {
|
||||
logger.error(`${logModule}: can't load extension main at ${extAbsolutePath}: ${error}`, { extension, error });
|
||||
if (ipcRenderer) {
|
||||
console.error(`${logModule}: can't load ${entryPointName} for "${extension.manifest.name}": ${error.stack || error}`, extension);
|
||||
} else {
|
||||
logger.error(`${logModule}: can't load ${entryPointName} for "${extension.manifest.name}": ${error}`, { extension });
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export * from "../../common/catalog/catalog-entity";
|
||||
@ -19,5 +19,10 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export * from "./registrations";
|
||||
export * from "./catalog";
|
||||
import { IpcMain as Ipc } from "../ipc/ipc-main";
|
||||
import { LensMainExtension as LensExtension } from "../lens-main-extension";
|
||||
|
||||
export {
|
||||
Ipc,
|
||||
LensExtension,
|
||||
};
|
||||
@ -26,10 +26,14 @@ import * as Component from "./components";
|
||||
import * as K8sApi from "./k8s-api";
|
||||
import * as Navigation from "./navigation";
|
||||
import * as Theme from "./theming";
|
||||
import { IpcRenderer as Ipc } from "../ipc/ipc-renderer";
|
||||
import { LensRendererExtension as LensExtension } from "../lens-renderer-extension";
|
||||
|
||||
export {
|
||||
Component,
|
||||
K8sApi,
|
||||
Navigation,
|
||||
Theme,
|
||||
Ipc,
|
||||
LensExtension,
|
||||
};
|
||||
|
||||
@ -23,7 +23,8 @@
|
||||
|
||||
import "../common/system-ca";
|
||||
import * as Mobx from "mobx";
|
||||
import * as LensExtensionsCoreApi from "../extensions/core-api";
|
||||
import * as LensExtensionsCommonApi from "../extensions/common-api";
|
||||
import * as LensExtensionsMainApi from "../extensions/main-api";
|
||||
import { app, autoUpdater, ipcMain, dialog, powerMonitor } from "electron";
|
||||
import { appName, isMac, productName } from "../common/vars";
|
||||
import path from "path";
|
||||
@ -279,7 +280,8 @@ app.on("open-url", (event, rawUrl) => {
|
||||
* e.g. global.Mobx, global.LensExtensions
|
||||
*/
|
||||
const LensExtensions = {
|
||||
...LensExtensionsCoreApi,
|
||||
Common: LensExtensionsCommonApi,
|
||||
Main: LensExtensionsMainApi,
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
@ -24,7 +24,7 @@ import * as uuid from "uuid";
|
||||
import { broadcastMessage } from "../../../common/ipc";
|
||||
import { ProtocolHandlerExtension, ProtocolHandlerInternal } from "../../../common/protocol-handler";
|
||||
import { noop } from "../../../common/utils";
|
||||
import { LensMainExtension } from "../../../extensions/core-api";
|
||||
import { LensExtension } from "../../../extensions/main-api";
|
||||
import { ExtensionLoader } from "../../../extensions/extension-loader";
|
||||
import { ExtensionsStore } from "../../../extensions/extensions-store";
|
||||
import { LensProtocolRouterMain } from "../router";
|
||||
@ -78,7 +78,7 @@ describe("protocol router tests", () => {
|
||||
|
||||
it.only("should not throw when has valid host", async () => {
|
||||
const extId = uuid.v4();
|
||||
const ext = new LensMainExtension({
|
||||
const ext = new LensExtension({
|
||||
id: extId,
|
||||
manifestPath: "/foo/bar",
|
||||
manifest: {
|
||||
@ -155,7 +155,7 @@ describe("protocol router tests", () => {
|
||||
|
||||
const lpr = LensProtocolRouterMain.getInstance();
|
||||
const extId = uuid.v4();
|
||||
const ext = new LensMainExtension({
|
||||
const ext = new LensExtension({
|
||||
id: extId,
|
||||
manifestPath: "/foo/bar",
|
||||
manifest: {
|
||||
@ -195,7 +195,7 @@ describe("protocol router tests", () => {
|
||||
|
||||
{
|
||||
const extId = uuid.v4();
|
||||
const ext = new LensMainExtension({
|
||||
const ext = new LensExtension({
|
||||
id: extId,
|
||||
manifestPath: "/foo/bar",
|
||||
manifest: {
|
||||
@ -219,7 +219,7 @@ describe("protocol router tests", () => {
|
||||
|
||||
{
|
||||
const extId = uuid.v4();
|
||||
const ext = new LensMainExtension({
|
||||
const ext = new LensExtension({
|
||||
id: extId,
|
||||
manifestPath: "/foo/bar",
|
||||
manifest: {
|
||||
|
||||
@ -26,7 +26,7 @@ import * as Mobx from "mobx";
|
||||
import * as MobxReact from "mobx-react";
|
||||
import * as ReactRouter from "react-router";
|
||||
import * as ReactRouterDom from "react-router-dom";
|
||||
import * as LensExtensionsCoreApi from "../extensions/core-api";
|
||||
import * as LensExtensionsCommonApi from "../extensions/common-api";
|
||||
import * as LensExtensionsRendererApi from "../extensions/renderer-api";
|
||||
import { render, unmountComponentAtNode } from "react-dom";
|
||||
import { delay } from "../common/utils";
|
||||
@ -123,8 +123,8 @@ bootstrap(process.isMainFrame ? LensApp : App);
|
||||
* e.g. Devtools -> Console -> window.LensExtensions (renderer)
|
||||
*/
|
||||
const LensExtensions = {
|
||||
...LensExtensionsCoreApi,
|
||||
...LensExtensionsRendererApi,
|
||||
Common: LensExtensionsCommonApi,
|
||||
Renderer: LensExtensionsRendererApi,
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user