diff --git a/build/set_build_version.ts b/build/set_build_version.ts
index df48a1da13..13d46d4ff3 100644
--- a/build/set_build_version.ts
+++ b/build/set_build_version.ts
@@ -22,6 +22,7 @@ import * as fs from "fs";
import * as path from "path";
import appInfo from "../package.json";
import semver from "semver";
+import fastGlob from "fast-glob";
const packagePath = path.join(__dirname, "../package.json");
const versionInfo = semver.parse(appInfo.version);
@@ -41,3 +42,14 @@ if (versionInfo.prerelease) {
fs.writeFileSync(packagePath, `${JSON.stringify(appInfo, null, 2)}\n`);
+
+const extensionManifests = fastGlob.sync(["extensions/*/package.json"]);
+
+for (const manifestPath of extensionManifests) {
+ const packagePath = path.join(__dirname, "..", manifestPath);
+
+ import(packagePath).then((packageInfo) => {
+ packageInfo.default.version = `${versionInfo.raw}.${Date.now()}`;
+ fs.writeFileSync(packagePath, `${JSON.stringify(packageInfo.default, null, 2)}\n`);
+ });
+}
diff --git a/docs/extensions/capabilities/common-capabilities.md b/docs/extensions/capabilities/common-capabilities.md
index 676603ce21..ffb066f72f 100644
--- a/docs/extensions/capabilities/common-capabilities.md
+++ b/docs/extensions/capabilities/common-capabilities.md
@@ -14,9 +14,9 @@ In order to see logs from this extension, you need to start Lens from the comman
This extension can register a custom callback that is executed when an extension is activated (started).
``` javascript
-import { LensMainExtension } from "@k8slens/extensions"
+import { Main } from "@k8slens/extensions"
-export default class ExampleMainExtension extends LensMainExtension {
+export default class ExampleMainExtension extends Main.LensExtension {
async onActivate() {
console.log("hello world")
}
@@ -28,9 +28,9 @@ export default class ExampleMainExtension extends LensMainExtension {
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
``` javascript
-import { LensMainExtension } from "@k8slens/extensions"
+import { Main } from "@k8slens/extensions"
-export default class ExampleMainExtension extends LensMainExtension {
+export default class ExampleMainExtension extends Main.LensExtension {
async onDeactivate() {
console.log("bye bye")
}
@@ -44,15 +44,15 @@ This extension can register custom app menus that will be displayed on OS native
Example:
```typescript
-import { LensMainExtension, windowManager } from "@k8slens/extensions"
+import { Main } from "@k8slens/extensions"
-export default class ExampleMainExtension extends LensMainExtension {
+export default class ExampleMainExtension extends Main.LensExtension {
appMenus = [
{
parentId: "help",
label: "Example item",
click() {
- windowManager.navigate("https://k8slens.dev");
+ Main.Navigation.navigate("https://k8slens.dev");
}
}
]
@@ -69,9 +69,9 @@ In order to see logs from this extension you need to check them via **View** > *
This extension can register a custom callback that is executed when an extension is activated (started).
``` javascript
-import { LensRendererExtension } from "@k8slens/extensions"
+import { Renderer } from "@k8slens/extensions"
-export default class ExampleExtension extends LensRendererExtension {
+export default class ExampleExtension extends Renderer.LensExtension {
async onActivate() {
console.log("hello world")
}
@@ -83,9 +83,9 @@ export default class ExampleExtension extends LensRendererExtension {
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
``` javascript
-import { LensRendererExtension } from "@k8slens/extensions"
+import { Renderer } from "@k8slens/extensions"
-export default class ExampleMainExtension extends LensRendererExtension {
+export default class ExampleMainExtension extends Renderer.LensExtension {
async onDeactivate() {
console.log("bye bye")
}
@@ -99,10 +99,16 @@ The global page is a full-screen page that hides all other content from a window
```typescript
import React from "react"
-import { Component, LensRendererExtension } from "@k8slens/extensions"
+import { Renderer } from "@k8slens/extensions"
import { ExamplePage } from "./src/example-page"
-export default class ExampleRendererExtension extends LensRendererExtension {
+const {
+ Component: {
+ Icon,
+ }
+} = Renderer;
+
+export default class ExampleRendererExtension extends Renderer.LensExtension {
globalPages = [
{
id: "example",
@@ -117,7 +123,7 @@ export default class ExampleRendererExtension extends LensRendererExtension {
title: "Example page", // used in icon's tooltip
target: { pageId: "example" }
components: {
- Icon: () =>
(path: str return parts.filter(Boolean).join(""); }; } + +export function buildURLPositional
(path: string | any) {
+ const builder = buildURL(path);
+
+ return function(params?: P, query?: Q, fragment?: string): string {
+ return builder({ params, query, fragment });
+ };
+}
diff --git a/src/common/vars.ts b/src/common/vars.ts
index 94ded7028e..6a55683d48 100644
--- a/src/common/vars.ts
+++ b/src/common/vars.ts
@@ -37,7 +37,7 @@ export const isPublishConfigured = Object.keys(packageInfo.build).includes("publ
export const productName = packageInfo.productName;
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
-export const publicPath = "/build/";
+export const publicPath = "/build/" as string;
// Webpack build paths
export const contextDir = process.cwd();
@@ -60,13 +60,13 @@ defineGlobal("__static", {
});
// Apis
-export const apiPrefix = "/api"; // local router apis
-export const apiKubePrefix = "/api-kube"; // k8s cluster apis
+export const apiPrefix = "/api" as string; // local router apis
+export const apiKubePrefix = "/api-kube" as string; // k8s cluster apis
// Links
-export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues";
-export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI";
-export const supportUrl = "https://docs.k8slens.dev/latest/support/";
+export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues" as string;
+export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI" as string;
+export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string;
// This explicitly ignores the prerelease info on the package version
const { major, minor, patch } = new SemVer(packageInfo.version);
diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts
index 8a0929d016..829e8a617f 100644
--- a/src/extensions/extension-discovery.ts
+++ b/src/extensions/extension-discovery.ts
@@ -34,6 +34,7 @@ import { extensionInstaller, PackageJson } from "./extension-installer";
import { ExtensionsStore } from "./extensions-store";
import { ExtensionLoader } from "./extension-loader";
import type { LensExtensionId, LensExtensionManifest } from "./lens-extension";
+import { isProduction } from "../common/vars";
export interface InstalledExtension {
id: LensExtensionId;
@@ -353,7 +354,7 @@ export class ExtensionDiscovery extends Singleton {
const isEnabled = isBundled || ExtensionsStore.getInstance().isEnabled(installedManifestPath);
const extensionDir = path.dirname(manifestPath);
const npmPackage = path.join(extensionDir, `${manifest.name}-${manifest.version}.tgz`);
- const absolutePath = (await fse.pathExists(npmPackage)) ? npmPackage : extensionDir;
+ const absolutePath = (isProduction && await fse.pathExists(npmPackage)) ? npmPackage : extensionDir;
return {
id: installedManifestPath,
diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts
index dc96b892f2..8651455380 100644
--- a/src/extensions/extension-loader.ts
+++ b/src/extensions/extension-loader.ts
@@ -279,6 +279,7 @@ export class ExtensionLoader extends Singleton {
registries.kubeObjectMenuRegistry.add(extension.kubeObjectMenuItems),
registries.kubeObjectDetailRegistry.add(extension.kubeObjectDetailItems),
registries.kubeObjectStatusRegistry.add(extension.kubeObjectStatusTexts),
+ registries.workloadsOverviewDetailRegistry.add(extension.kubeWorkloadsOverviewItems),
registries.commandRegistry.add(extension.commands),
];
diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts
index 520ffae05b..e9105dbcd9 100644
--- a/src/extensions/lens-renderer-extension.ts
+++ b/src/extensions/lens-renderer-extension.ts
@@ -21,7 +21,7 @@
import type {
AppPreferenceRegistration, ClusterPageMenuRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration,
- KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, WelcomeMenuRegistration,
+ KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, WelcomeMenuRegistration, WorkloadsOverviewDetailRegistration,
} from "./registries";
import type { Cluster } from "../main/cluster";
import { LensExtension } from "./lens-extension";
@@ -40,6 +40,7 @@ export class LensRendererExtension extends LensExtension {
statusBarItems: StatusBarRegistration[] = [];
kubeObjectDetailItems: KubeObjectDetailRegistration[] = [];
kubeObjectMenuItems: KubeObjectMenuRegistration[] = [];
+ kubeWorkloadsOverviewItems: WorkloadsOverviewDetailRegistration[] = [];
commands: CommandRegistration[] = [];
welcomeMenus: WelcomeMenuRegistration[] = [];
diff --git a/src/extensions/main-api/index.ts b/src/extensions/main-api/index.ts
index 72102ebc24..a596e8169e 100644
--- a/src/extensions/main-api/index.ts
+++ b/src/extensions/main-api/index.ts
@@ -20,11 +20,13 @@
*/
import * as Catalog from "./catalog";
+import * as Navigation from "./navigation";
import { IpcMain as Ipc } from "../ipc/ipc-main";
import { LensMainExtension as LensExtension } from "../lens-main-extension";
export {
Catalog,
+ Navigation,
Ipc,
LensExtension,
};
diff --git a/src/extensions/main-api/navigation.ts b/src/extensions/main-api/navigation.ts
new file mode 100644
index 0000000000..95ae718b33
--- /dev/null
+++ b/src/extensions/main-api/navigation.ts
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+import { WindowManager } from "../../main/window-manager";
+
+export function navigate(url: string) {
+ return WindowManager.getInstance().navigate(url);
+}
diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts
index 7056206daf..e3a6490d61 100644
--- a/src/extensions/registries/index.ts
+++ b/src/extensions/registries/index.ts
@@ -33,3 +33,4 @@ export * from "./command-registry";
export * from "./entity-setting-registry";
export * from "./welcome-menu-registry";
export * from "./protocol-handler-registry";
+export * from "./workloads-overview-detail-registry";
diff --git a/src/extensions/registries/workloads-overview-detail-registry.ts b/src/extensions/registries/workloads-overview-detail-registry.ts
new file mode 100644
index 0000000000..8ad2a10e19
--- /dev/null
+++ b/src/extensions/registries/workloads-overview-detail-registry.ts
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+import type React from "react";
+import { BaseRegistry } from "./base-registry";
+
+export interface WorkloadsOverviewDetailComponents {
+ Details: React.ComponentType