diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
index 02ae36727e..f7b3529b74 100644
--- a/.github/release-drafter.yml
+++ b/.github/release-drafter.yml
@@ -18,13 +18,3 @@ template: |
## Changes since $PREVIOUS_TAG
$CHANGES
-
- ### Download
-
- - Lens v$RESOLVED_VERSION - Linux
- - [AppImage](https://github.com/lensapp/lens/releases/download/v$RESOLVED_VERSION/Lens-$RESOLVED_VERSION.x86_64.AppImage)
- - [DEB](https://github.com/lensapp/lens/releases/download/v$RESOLVED_VERSION/Lens-$RESOLVED_VERSION.amd64.deb)
- - [RPM](https://github.com/lensapp/lens/releases/download/v$RESOLVED_VERSION/Lens-$RESOLVED_VERSION.x86_64.rpm)
- - [Snapcraft](https://snapcraft.io/kontena-lens)
- - [Lens v$RESOLVED_VERSION - MacOS](https://github.com/lensapp/lens/releases/download/v$RESOLVED_VERSION/Lens-$RESOLVED_VERSION.dmg)
- - [Lens v$RESOLVED_VERSION - Windows](https://github.com/lensapp/lens/releases/download/v$RESOLVED_VERSION/Lens-Setup-$RESOLVED_VERSION.exe)
diff --git a/Makefile b/Makefile
index 428a70ae23..d8a6a35462 100644
--- a/Makefile
+++ b/Makefile
@@ -73,10 +73,10 @@ else
endif
$(extension_node_modules):
- cd $(@:/node_modules=) && npm install --no-audit --no-fund
+ cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund
$(extension_dists): src/extensions/npm/extensions/dist
- cd $(@:/dist=) && npm run build
+ cd $(@:/dist=) && ../../node_modules/.bin/npm run build
.PHONY: build-extensions
build-extensions: node_modules $(extension_node_modules) $(extension_dists)
@@ -104,8 +104,8 @@ build-npm: build-extension-types copy-extension-themes src/extensions/npm/extens
build-extension-types: src/extensions/npm/extensions/dist
.PHONY: publish-npm
-publish-npm: build-npm
- npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
+publish-npm: node_modules build-npm
+ ./node_modules/.bin/npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
cd src/extensions/npm/extensions && npm publish --access=public
.PHONY: docs
diff --git a/package.json b/package.json
index 0527ff362c..cec4e86300 100644
--- a/package.json
+++ b/package.json
@@ -327,7 +327,7 @@
"prettier": "^2.2.0",
"progress-bar-webpack-plugin": "^2.1.0",
"raw-loader": "^4.0.1",
- "react-beautiful-dnd": "^13.0.0",
+ "react-beautiful-dnd": "^13.1.0",
"react-refresh": "^0.9.0",
"react-router-dom": "^5.2.0",
"react-select": "^3.1.0",
@@ -341,7 +341,7 @@
"ts-jest": "^26.1.0",
"ts-loader": "^7.0.5",
"ts-node": "^8.10.2",
- "type-fest": "^0.18.0",
+ "type-fest": "^1.0.2",
"typedoc": "0.17.0-3",
"typedoc-plugin-markdown": "^2.4.0",
"typeface-roboto": "^0.0.75",
diff --git a/src/common/catalog-entities/icons/kubernetes.svg b/src/common/catalog-entities/icons/kubernetes.svg
new file mode 100644
index 0000000000..b4a9068420
--- /dev/null
+++ b/src/common/catalog-entities/icons/kubernetes.svg
@@ -0,0 +1,46 @@
+
+
+
diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts
index 29b8940a53..6857f4ef6b 100644
--- a/src/common/catalog-entities/kubernetes-cluster.ts
+++ b/src/common/catalog-entities/kubernetes-cluster.ts
@@ -87,7 +87,8 @@ export class KubernetesClusterCategory extends EventEmitter implements CatalogCa
public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
public readonly kind = "CatalogCategory";
public metadata = {
- name: "Kubernetes Clusters"
+ name: "Kubernetes Clusters",
+ icon: require(`!!raw-loader!./icons/kubernetes.svg`).default // eslint-disable-line
};
public spec = {
group: "entity.k8slens.dev",
diff --git a/src/common/catalog-entities/web-link.ts b/src/common/catalog-entities/web-link.ts
index 86a1a991c2..a2204ea3e8 100644
--- a/src/common/catalog-entities/web-link.ts
+++ b/src/common/catalog-entities/web-link.ts
@@ -49,7 +49,8 @@ export class WebLinkCategory implements CatalogCategory {
public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
public readonly kind = "CatalogCategory";
public metadata = {
- name: "Web Links"
+ name: "Web Links",
+ icon: "link"
};
public spec = {
group: "entity.k8slens.dev",
diff --git a/src/common/catalog-entity.ts b/src/common/catalog-entity.ts
index 8430381368..f18f0fccca 100644
--- a/src/common/catalog-entity.ts
+++ b/src/common/catalog-entity.ts
@@ -8,6 +8,7 @@ export interface CatalogCategory {
kind: string;
metadata: {
name: string;
+ icon: string;
}
spec: {
group: string;
diff --git a/src/extensions/registries/entity-setting-registry.ts b/src/extensions/registries/entity-setting-registry.ts
index 8dd5ce6f25..9ad873ce67 100644
--- a/src/extensions/registries/entity-setting-registry.ts
+++ b/src/extensions/registries/entity-setting-registry.ts
@@ -15,8 +15,9 @@ export interface EntitySettingRegistration {
kind: string;
apiVersions: string[];
source?: string;
- id?: string;
components: EntitySettingComponents;
+ id?: string;
+ priority?: number;
}
export interface RegisteredEntitySetting extends EntitySettingRegistration {
@@ -32,17 +33,21 @@ export class EntitySettingRegistry extends BaseRegistry {
+ let items = this.getItems().filter((item) => {
return item.kind === kind && item.apiVersions.includes(apiVersion);
+ }).map((item) => {
+ item.priority = item.priority ?? 50;
+
+ return item;
});
if (source) {
- return items.filter((item) => {
+ items = items.filter((item) => {
return !item.source || item.source === source;
});
- } else {
- return items;
}
+
+ return items.sort((a, b) => b.priority - a.priority);
}
}
diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts
index 5761ac5dec..53826bf1bf 100644
--- a/src/main/helm/helm-repo-manager.ts
+++ b/src/main/helm/helm-repo-manager.ts
@@ -35,7 +35,7 @@ export class HelmRepoManager extends Singleton {
protected helmEnv: HelmEnv;
protected initialized: boolean;
- async loadAvailableRepos(): Promise {
+ public static async loadAvailableRepos(): Promise {
const res = await customRequestPromise({
uri: "https://github.com/lensapp/artifact-hub-repositories/releases/download/latest/repositories.json",
json: true,
@@ -46,18 +46,18 @@ export class HelmRepoManager extends Singleton {
return orderBy(res.body, repo => repo.name);
}
- async init() {
+ private async init() {
helmCli.setLogger(logger);
await helmCli.ensureBinary();
if (!this.initialized) {
- this.helmEnv = await this.parseHelmEnv();
- await this.update();
+ this.helmEnv = await HelmRepoManager.parseHelmEnv();
+ await HelmRepoManager.update();
this.initialized = true;
}
}
- protected async parseHelmEnv() {
+ protected static async parseHelmEnv() {
const helm = await helmCli.binaryPath();
const { stdout } = await promiseExec(`"${helm}" env`).catch((error) => {
throw(error.stderr);
@@ -78,6 +78,10 @@ export class HelmRepoManager extends Singleton {
public async repositories(): Promise {
try {
+ if (!this.initialized) {
+ await this.init();
+ }
+
const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG;
const { repositories }: HelmRepoConfig = await readFile(repoConfigFile, "utf8")
.then((yamlContent: string) => yaml.safeLoad(yamlContent))
@@ -86,7 +90,7 @@ export class HelmRepoManager extends Singleton {
}));
if (!repositories.length) {
- await this.addRepo({ name: "bitnami", url: "https://charts.bitnami.com/bitnami" });
+ await HelmRepoManager.addRepo({ name: "bitnami", url: "https://charts.bitnami.com/bitnami" });
return await this.repositories();
}
@@ -102,13 +106,7 @@ export class HelmRepoManager extends Singleton {
}
}
- public async repository(name: string) {
- const repositories = await this.repositories();
-
- return repositories.find(repo => repo.name == name);
- }
-
- public async update() {
+ public static async update() {
const helm = await helmCli.binaryPath();
const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => {
return { stdout: error.stdout };
@@ -117,7 +115,7 @@ export class HelmRepoManager extends Singleton {
return stdout;
}
- public async addRepo({ name, url }: HelmRepo) {
+ public static async addRepo({ name, url }: HelmRepo) {
logger.info(`[HELM]: adding repo "${name}" from ${url}`);
const helm = await helmCli.binaryPath();
const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => {
@@ -127,7 +125,7 @@ export class HelmRepoManager extends Singleton {
return stdout;
}
- public async addСustomRepo(repoAttributes : HelmRepo) {
+ public static async addСustomRepo(repoAttributes : HelmRepo) {
logger.info(`[HELM]: adding repo "${repoAttributes.name}" from ${repoAttributes.url}`);
const helm = await helmCli.binaryPath();
@@ -146,7 +144,7 @@ export class HelmRepoManager extends Singleton {
return stdout;
}
- public async removeRepo({ name, url }: HelmRepo): Promise {
+ public static async removeRepo({ name, url }: HelmRepo): Promise {
logger.info(`[HELM]: removing repo "${name}" from ${url}`);
const helm = await helmCli.binaryPath();
const { stdout } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => {
diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts
index 9a42616c89..e933447593 100644
--- a/src/main/helm/helm-service.ts
+++ b/src/main/helm/helm-service.ts
@@ -34,7 +34,8 @@ class HelmService {
readme: "",
versions: {}
};
- const repo = await HelmRepoManager.getInstance().repository(repoName);
+ const repos = await HelmRepoManager.getInstance().repositories();
+ const repo = repos.find(repo => repo.name === repoName);
const chartManager = new HelmChartManager(repo);
const chart = await chartManager.chart(chartName);
@@ -45,7 +46,8 @@ class HelmService {
}
public async getChartValues(repoName: string, chartName: string, version = "") {
- const repo = await HelmRepoManager.getInstance().repository(repoName);
+ const repos = await HelmRepoManager.getInstance().repositories();
+ const repo = repos.find(repo => repo.name === repoName);
const chartManager = new HelmChartManager(repo);
return chartManager.getValues(chartName, version);
diff --git a/src/main/index.ts b/src/main/index.ts
index c1d99cbd76..2eeeb76636 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -33,6 +33,7 @@ import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
import { CatalogPusher } from "./catalog-pusher";
import { catalogEntityRegistry } from "../common/catalog-entity-registry";
import { HotbarStore } from "../common/hotbar-store";
+import { HelmRepoManager } from "./helm/helm-repo-manager";
const workingDir = path.join(app.getPath("appData"), appName);
@@ -105,6 +106,8 @@ app.on("ready", async () => {
const extensionsStore = ExtensionsStore.createInstance();
const filesystemStore = FilesystemProvisionerStore.createInstance();
+ HelmRepoManager.createInstance(); // create the instance
+
logger.info("💾 Loading stores");
// preload
await Promise.all([
diff --git a/src/renderer/api/catalog-category-registry.ts b/src/renderer/api/catalog-category-registry.ts
new file mode 100644
index 0000000000..2e80789851
--- /dev/null
+++ b/src/renderer/api/catalog-category-registry.ts
@@ -0,0 +1 @@
+export { catalogCategoryRegistry } from "../../common/catalog-category-registry";
diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx
index 18cc3e92a5..f856d50f1e 100644
--- a/src/renderer/bootstrap.tsx
+++ b/src/renderer/bootstrap.tsx
@@ -60,7 +60,8 @@ export async function bootstrap(App: AppComponent) {
const filesystemStore = FilesystemProvisionerStore.createInstance();
const themeStore = ThemeStore.createInstance();
const hotbarStore = HotbarStore.createInstance();
- const helmRepoManager = HelmRepoManager.createInstance();
+
+ HelmRepoManager.createInstance(); // initialize the manager
// preload common stores
await Promise.all([
@@ -70,7 +71,6 @@ export async function bootstrap(App: AppComponent) {
extensionsStore.load(),
filesystemStore.load(),
themeStore.init(),
- helmRepoManager.init(),
]);
// Register additional store listeners
diff --git a/src/renderer/components/+catalog/catalog-entity.store.ts b/src/renderer/components/+catalog/catalog-entity.store.ts
index 30983f1456..239c93f717 100644
--- a/src/renderer/components/+catalog/catalog-entity.store.ts
+++ b/src/renderer/components/+catalog/catalog-entity.store.ts
@@ -45,6 +45,15 @@ export class CatalogEntityItem implements ItemObject {
return this.entity.metadata.source || "unknown";
}
+ get searchFields() {
+ return [
+ this.name,
+ this.id,
+ this.phase,
+ ...this.labels.map((value, key) => `${key}=${value}`)
+ ];
+ }
+
onRun(ctx: CatalogEntityActionContext) {
this.entity.onRun(ctx);
}
diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx
index e81004e97a..93fa7f213c 100644
--- a/src/renderer/components/+catalog/catalog.tsx
+++ b/src/renderer/components/+catalog/catalog.tsx
@@ -168,9 +168,12 @@ export class Catalog extends React.Component {
[sortBy.source]: (item: CatalogEntityItem) => item.source,
[sortBy.status]: (item: CatalogEntityItem) => item.phase,
}}
+ searchFilters={[
+ (entity: CatalogEntityItem) => entity.searchFields,
+ ]}
renderTableHeader={[
{ title: "Name", className: "name", sortBy: sortBy.name },
- { title: "Source", className: "source" },
+ { title: "Source", className: "source", sortBy: sortBy.source },
{ title: "Labels", className: "labels" },
{ title: "Status", className: "status", sortBy: sortBy.status },
]}
diff --git a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx
index 21fc6cd9fa..5ffec819f8 100644
--- a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx
+++ b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx
@@ -84,7 +84,7 @@ export class AddHelmRepoDialog extends React.Component {
async addCustomRepo() {
try {
- await HelmRepoManager.getInstance().addСustomRepo(this.helmRepo);
+ await HelmRepoManager.addСustomRepo(this.helmRepo);
Notifications.ok(<>Helm repository {this.helmRepo.name} has added>);
this.props.onAddRepo();
this.close();
diff --git a/src/renderer/components/+preferences/helm-charts.tsx b/src/renderer/components/+preferences/helm-charts.tsx
index 67661fa549..e86badeb7d 100644
--- a/src/renderer/components/+preferences/helm-charts.tsx
+++ b/src/renderer/components/+preferences/helm-charts.tsx
@@ -39,7 +39,7 @@ export class HelmCharts extends React.Component {
try {
if (!this.repos.length) {
- this.repos = await HelmRepoManager.getInstance().loadAvailableRepos(); // via https://helm.sh
+ this.repos = await HelmRepoManager.loadAvailableRepos();
}
const repos = await HelmRepoManager.getInstance().repositories(); // via helm-cli
@@ -54,7 +54,7 @@ export class HelmCharts extends React.Component {
async addRepo(repo: HelmRepo) {
try {
- await HelmRepoManager.getInstance().addRepo(repo);
+ await HelmRepoManager.addRepo(repo);
this.addedRepos.set(repo.name, repo);
} catch (err) {
Notifications.error(<>Adding helm branch {repo.name} has failed: {String(err)}>);
@@ -63,7 +63,7 @@ export class HelmCharts extends React.Component {
async removeRepo(repo: HelmRepo) {
try {
- await HelmRepoManager.getInstance().removeRepo(repo);
+ await HelmRepoManager.removeRepo(repo);
this.addedRepos.delete(repo.name);
} catch (err) {
Notifications.error(
diff --git a/src/renderer/components/hotbar/hotbar-icon.scss b/src/renderer/components/hotbar/hotbar-icon.scss
index bce7070ad1..80252addae 100644
--- a/src/renderer/components/hotbar/hotbar-icon.scss
+++ b/src/renderer/components/hotbar/hotbar-icon.scss
@@ -38,6 +38,22 @@
}
}
+ .badge {
+ color: $textColorAccent;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ margin: -$padding;
+ font-size: $font-size-small;
+ background: $clusterMenuBackground;
+ color: white;
+ padding: 0px;
+ border-radius: 50%;
+ svg {
+ width: 13px;
+ }
+ }
+
img {
width: var(--size);
height: var(--size);
diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx
index b11c5975d9..45f9535644 100644
--- a/src/renderer/components/hotbar/hotbar-icon.tsx
+++ b/src/renderer/components/hotbar/hotbar-icon.tsx
@@ -12,6 +12,7 @@ import { observable, makeObservable } from "mobx";
import { navigate } from "../../navigation";
import { HotbarStore } from "../../../common/hotbar-store";
import { ConfirmDialog } from "../confirm-dialog";
+import { catalogCategoryRegistry } from "../../api/catalog-category-registry";
interface Props extends DOMAttributes {
entity: CatalogEntity;
@@ -60,6 +61,21 @@ export class HotbarIcon extends React.Component {
}
}
+ get badgeIcon() {
+ const className = "badge";
+ const category = catalogCategoryRegistry.getCategoryForEntity(this.props.entity);
+
+ if (!category) {
+ return ;
+ }
+
+ if (category.metadata.icon.includes(";
+ } else {
+ return ;
+ }
+ }
+
toggleMenu() {
this.menuOpen = !this.menuOpen;
}
@@ -111,6 +127,7 @@ export class HotbarIcon extends React.Component {
{entity.metadata.name}
{this.iconString}
+ { this.badgeIcon }