diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index f7b3529b74..93536874e2 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -10,6 +10,7 @@ categories: - title: '🧰 Maintenance' labels: - 'chore' + - 'area/documentation' - 'area/ci' - 'area/tests' - 'dependencies' diff --git a/Makefile b/Makefile index f2c9d0eb13..883968feda 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ release-version: .PHONY: tag-release tag-release: - scripts/tag-release.sh + scripts/tag-release.sh $(CMD_ARGS) .PHONY: test test: binaries/client diff --git a/build/set_build_version.ts b/build/set_build_version.ts index 80fd385c59..a4c45dd167 100644 --- a/build/set_build_version.ts +++ b/build/set_build_version.ts @@ -33,6 +33,7 @@ function getBuildChannel(): string { * Note: it is by design that we don't use `rc` as a build channel for these versions */ switch (versionInfo.prerelease?.[0]) { + case "rc": case "beta": return "beta"; case undefined: diff --git a/docs/extensions/guides/images/clusterpagemenus.png b/docs/extensions/guides/images/clusterpagemenus.png index 3ed1c79e5b..77a3ec118a 100644 Binary files a/docs/extensions/guides/images/clusterpagemenus.png and b/docs/extensions/guides/images/clusterpagemenus.png differ diff --git a/docs/extensions/guides/renderer-extension.md b/docs/extensions/guides/renderer-extension.md index 110cf3331f..527dc0c623 100644 --- a/docs/extensions/guides/renderer-extension.md +++ b/docs/extensions/guides/renderer-extension.md @@ -60,7 +60,7 @@ Implementing `onDeactivate()` gives you the opportunity to clean up after your e 1. Navigate to **File** > **Extensions** in the top menu bar. (On Mac, it is **Lens** > **Extensions**.) - 2. Click **Disable** on the extension you want to disable. + 2. For the extension you want to disable, open the context menu (click on the three vertical dots) and choose **Disable**. The example above logs messages when the extension is enabled and disabled. @@ -71,7 +71,7 @@ Use cluster pages to display information about or add functionality to the activ It is also possible to include custom details from other clusters. Use your extension to access Kubernetes resources in the active cluster with [`ClusterStore.getInstance()`](../stores#Clusterstore). -Add a cluster page definition to a `LensRendererExtension` subclass with the following example: +Add a cluster page definition to a `Renderer.LensExtension` subclass with the following example: ```typescript import { Renderer } from "@k8slens/extensions"; @@ -124,7 +124,7 @@ Use `clusterPageMenus`, covered in the next section, to add cluster pages to the ### `clusterPageMenus` -`clusterPageMenus` allows you to add cluster page menu items to the secondary left nav. +`clusterPageMenus` allows you to add cluster page menu items to the secondary left nav, below Lens's standard cluster menus like **Workloads**, **Custom Resources**, etc. By expanding on the above example, you can add a cluster page menu item to the `ExampleExtension` definition: @@ -266,18 +266,18 @@ Activating this menu item toggles on and off the appearance of the submenu below The remaining two cluster page menu objects define the contents of the submenu. A cluster page menu object is defined to be a submenu item by setting the `parentId` field to the id of the parent of a foldout submenu, `"example"` in this case. -This is what the example will look like, including how the menu item will appear in the secondary left nav: +This is what the example could look like, including how the menu item will appear in the secondary left nav: + +![Cluster Page Menus](images/clusterpagemenus.png) ### `globalPages` Global pages are independent of the cluster dashboard and can fill the entire Lens UI. -Their primary use is to display information and provide functionality across clusters, including customized data and functionality unique to your extension. +Their primary use is to display information and provide functionality across clusters (or catalog entities), including customized data and functionality unique to your extension. -Typically, you would use a [global page menu](#globalpagemenus) located in the left nav to trigger a global page. -You can also trigger a global page with a [custom app menu selection](../main-extension#appmenus) from a Main Extension or a [custom status bar item](#statusbaritems). -Unlike cluster pages, users can trigger global pages even when there is no active cluster. +Unlike cluster pages, users can trigger global pages even when there is no active cluster (or catalog entity). -The following example defines a `LensRendererExtension` subclass with a single global page definition: +The following example defines a `Renderer.LensExtension` subclass with a single global page definition: ```typescript import { Renderer } from '@k8slens/extensions'; @@ -326,11 +326,11 @@ This allows the `HelpExtension` object to be passed in the global page definitio This way, `HelpPage` can access all `HelpExtension` subclass data. This example code shows how to create a global page, but not how to make that page available to the Lens user. -Global pages can be made available in the following ways: +Global pages are typically made available in the following ways: * To add global pages to the top menu bar, see [`appMenus`](../main-extension#appmenus) in the Main Extension guide. * To add global pages as an interactive element in the blue status bar along the bottom of the Lens UI, see [`statusBarItems`](#statusbaritems). -* To add global pages to the left side menu, see [`globalPageMenus`](#globalpagemenus). +* To add global pages to the Welcome Page, see [`welcomeMenus`](#welcomemenus). ### `welcomeMenus` ### `appPreferences` @@ -381,6 +381,7 @@ In this example `ExamplePreferenceInput`, `ExamplePreferenceHint`, and `ExampleP ```typescript import { Renderer } from "@k8slens/extensions"; +import { makeObservable } from "mobx"; import { observer } from "mobx-react"; import React from "react"; @@ -399,6 +400,11 @@ export class ExamplePreferenceProps { @observer export class ExamplePreferenceInput extends React.Component { + public constructor() { + super({preference: { enabled: false}}); + makeObservable(this); + } + render() { const { preference } = this.props; return ( @@ -432,7 +438,7 @@ It is used to indicate the state of the preference, and it is bound to the check `ExamplePreferenceHint` is a simple text span. -The above example introduces the decorators `observable` and `observer` from the [`mobx`](https://mobx.js.org/README.html) and [`mobx-react`](https://github.com/mobxjs/mobx-react#mobx-react) packages. +The above example introduces the decorators `makeObservable` and `observer` from the [`mobx`](https://mobx.js.org/README.html) and [`mobx-react`](https://github.com/mobxjs/mobx-react#mobx-react) packages. `mobx` simplifies state management. Without it, this example would not visually update the checkbox properly when the user activates it. [Lens uses `mobx`](../working-with-mobx) extensively for state management of its own UI elements. diff --git a/package.json b/package.json index 7a71c0dd8e..7a3141668f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.0.0-beta.11", + "version": "5.0.0-beta.10", "main": "static/build/main.js", "copyright": "© 2021 OpenLens Authors", "license": "MIT", diff --git a/scripts/tag-release.sh b/scripts/tag-release.sh index 82b7f14e6c..ce2ddffb2b 100755 --- a/scripts/tag-release.sh +++ b/scripts/tag-release.sh @@ -1,10 +1,21 @@ #!/bin/bash +while [[ $# -gt 0 ]]; do + key="$1" + + case $key in + -f|--force) + FORCE="--force" + shift # past argument + ;; + esac +done + if [[ `git branch --show-current` =~ ^release/v ]] then VERSION_STRING=$(cat package.json | jq '.version' -r | xargs printf "v%s") - git tag ${VERSION_STRING} - git push ${GIT_REMOTE:-origin} ${VERSION_STRING} + git tag ${VERSION_STRING} ${FORCE} + git push ${GIT_REMOTE:-origin} ${VERSION_STRING} ${FORCE} else echo "You must be in a release branch" fi diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index 322675b23a..e1766c1bb0 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -38,9 +38,6 @@ export interface KubernetesClusterPrometheusMetrics { prefix: string; }; type?: string; - icon?: { - src?: string; - }; } export interface KubernetesClusterSpec extends CatalogEntitySpec { @@ -49,7 +46,13 @@ export interface KubernetesClusterSpec extends CatalogEntitySpec { metrics?: { source: string; prometheus?: KubernetesClusterPrometheusMetrics; - } + }; + icon?: { + // TODO: move to CatalogEntitySpec once any-entity icons are supported + src?: string; + material?: string; + background?: string; + }; } export interface KubernetesClusterStatus extends CatalogEntityStatus { diff --git a/src/common/protocol-handler/router.ts b/src/common/protocol-handler/router.ts index 50f971c356..ea74d7ea0a 100644 --- a/src/common/protocol-handler/router.ts +++ b/src/common/protocol-handler/router.ts @@ -187,7 +187,7 @@ export abstract class LensProtocolRouter extends Singleton { return name; } - if (!ExtensionsStore.getInstance().isEnabled(extension.id)) { + if (!extension.isBundled && !ExtensionsStore.getInstance().isEnabled(extension.id)) { logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but not enabled`); return name; diff --git a/src/extensions/npm/extensions/package.json b/src/extensions/npm/extensions/package.json index 6857b12dda..594f26f56e 100644 --- a/src/extensions/npm/extensions/package.json +++ b/src/extensions/npm/extensions/package.json @@ -19,6 +19,7 @@ "@types/node": "*", "@types/react-select": "*", "@material-ui/core": "*", - "conf": "^7.0.1" + "conf": "^7.0.1", + "typed-emitter": "^1.3.1" } } diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 66c9bda601..b15cce8ae7 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -102,7 +102,7 @@ export class ClusterManager extends Singleton { const entity = catalogEntityRegistry.items[index] as KubernetesCluster; this.updateEntityStatus(entity, cluster); - + entity.metadata.labels = Object.assign({}, cluster.labels, entity.metadata.labels); if (cluster.preferences?.clusterName) { @@ -119,7 +119,12 @@ export class ClusterManager extends Singleton { entity.spec.metrics.prometheus = prometheus; } - entity.spec.icon.src = cluster.preferences.icon; + if (cluster.preferences.icon) { + entity.spec.icon ??= {}; + entity.spec.icon.src = cluster.preferences.icon; + } else { + entity.spec.icon = null; + } catalogEntityRegistry.items.splice(index, 1, entity); } diff --git a/src/main/protocol-handler/router.ts b/src/main/protocol-handler/router.ts index 6a8090617b..cbd609a9ff 100644 --- a/src/main/protocol-handler/router.ts +++ b/src/main/protocol-handler/router.ts @@ -82,10 +82,10 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { throw new proto.RoutingError(proto.RoutingErrorType.INVALID_PROTOCOL, url); } + WindowManager.getInstance(false)?.ensureMainWindow().catch(noop); const routeInternally = checkHost(url); logger.info(`${proto.LensProtocolRouter.LoggingPrefix}: routing ${url.toString()}`); - WindowManager.getInstance(false)?.ensureMainWindow().catch(noop); if (routeInternally) { this._routeToInternal(url); diff --git a/src/migrations/hotbar-store/5.0.0-beta.11.ts b/src/migrations/hotbar-store/5.0.0-beta.10.ts similarity index 99% rename from src/migrations/hotbar-store/5.0.0-beta.11.ts rename to src/migrations/hotbar-store/5.0.0-beta.10.ts index 9ad4feb0bf..fe1b06f320 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.11.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.10.ts @@ -35,7 +35,7 @@ interface Pre500WorkspaceStoreModel { } export default { - version: "5.0.0-beta.11", + version: "5.0.0-beta.10", run(store) { const hotbars: Hotbar[] = store.get("hotbars"); const userDataPath = app.getPath("userData"); diff --git a/src/migrations/hotbar-store/index.ts b/src/migrations/hotbar-store/index.ts index a18a27bcad..44c5ebcdf4 100644 --- a/src/migrations/hotbar-store/index.ts +++ b/src/migrations/hotbar-store/index.ts @@ -26,11 +26,11 @@ import { joinMigrations } from "../helpers"; import version500alpha0 from "./5.0.0-alpha.0"; import version500alpha2 from "./5.0.0-alpha.2"; import version500beta5 from "./5.0.0-beta.5"; -import version500beta11 from "./5.0.0-beta.11"; +import version500beta10 from "./5.0.0-beta.10"; export default joinMigrations( version500alpha0, version500alpha2, version500beta5, - version500beta11, + version500beta10, ); diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index d7b6b76279..e5bda1f873 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -208,7 +208,7 @@ export class ReleaseDetails extends Component { {items.map(item => { const name = item.getName(); const namespace = item.getNs(); - const api = apiManager.getApi(item.metadata.selfLink); + const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == item.apiVersion); const detailsUrl = api ? getDetailsUrl(api.getUrl({ name, namespace })) : ""; return ( diff --git a/src/renderer/components/avatar/avatar.tsx b/src/renderer/components/avatar/avatar.tsx index cd27497bbb..4164b65261 100644 --- a/src/renderer/components/avatar/avatar.tsx +++ b/src/renderer/components/avatar/avatar.tsx @@ -72,9 +72,21 @@ function getIconString(title: string) { export function Avatar(props: Props) { const { title, width = 32, height = 32, colorHash, children, background, ...settings } = props; + const getBackgroundColor = () => { + if (background) { + return background; + } + + if (settings.src) { + return "transparent"; + } + + return randomColor({ seed: colorHash, luminosity: "dark" }); + }; + const generateAvatarStyle = (): React.CSSProperties => { return { - backgroundColor: background || randomColor({ seed: colorHash, luminosity: "dark" }), + backgroundColor: getBackgroundColor(), width, height, textTransform: "uppercase" diff --git a/src/renderer/ipc/index.tsx b/src/renderer/ipc/index.tsx index 51a50f1b01..338f71c38d 100644 --- a/src/renderer/ipc/index.tsx +++ b/src/renderer/ipc/index.tsx @@ -59,8 +59,8 @@ function UpdateAvailableHandler(event: IpcRendererEvent, ...[backchannel, update (
Update Available -

Version {updateInfo.version} of Lens IDE is now available. Would you like to update?

-

Manual restart required!

+

Version {updateInfo.version} of Lens IDE is available and ready to be installed. Would you like to update now?

+

Lens should restart automatically, if it doesn't please restart manually. Installed extensions might require updating.