mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix runtime errors on renderer
- remove all static uses of `createPageParam` (and then removed the legacy global) - Made LensRendererExtension and LensMainExtension just used dependencies and not the getLegacyDi - Fixed circular dep in extension-loader Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
fd86ea0d97
commit
a12bda2fc4
@ -259,6 +259,10 @@ module.exports = {
|
|||||||
"name": ".",
|
"name": ".",
|
||||||
"message": "No importing from local index.ts(x?) file. A common way to make circular dependencies.",
|
"message": "No importing from local index.ts(x?) file. A common way to make circular dependencies.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "..",
|
||||||
|
"message": "No importing from parent index.ts(x?) file. A common way to make circular dependencies.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,9 +3,9 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import packageInfo from "../package.json";
|
import packageInfo from "../package.json";
|
||||||
import { type WriteStream } from "fs";
|
|
||||||
import type { FileHandle } from "fs/promises";
|
import type { FileHandle } from "fs/promises";
|
||||||
import { open } from "fs/promises";
|
import { open } from "fs/promises";
|
||||||
|
import type { WriteStream } from "fs-extra";
|
||||||
import { constants, ensureDir, unlink } from "fs-extra";
|
import { constants, ensureDir, unlink } from "fs-extra";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
@ -17,6 +17,7 @@ import AbortController from "abort-controller";
|
|||||||
import { extract } from "tar-stream";
|
import { extract } from "tar-stream";
|
||||||
import gunzip from "gunzip-maybe";
|
import gunzip from "gunzip-maybe";
|
||||||
import { getBinaryName, normalizedPlatform } from "../src/common/vars";
|
import { getBinaryName, normalizedPlatform } from "../src/common/vars";
|
||||||
|
import { isErrnoException } from "../src/common/utils";
|
||||||
|
|
||||||
const pipeline = promisify(_pipeline);
|
const pipeline = promisify(_pipeline);
|
||||||
|
|
||||||
@ -44,6 +45,10 @@ abstract class BinaryDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ensureBinary(): Promise<void> {
|
async ensureBinary(): Promise<void> {
|
||||||
|
if (process.env.LENS_SKIP_DOWNLOAD_BINARIES === "true") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const stream = await fetch(this.url, {
|
const stream = await fetch(this.url, {
|
||||||
timeout: 15 * 60 * 1000, // 15min
|
timeout: 15 * 60 * 1000, // 15min
|
||||||
@ -51,7 +56,7 @@ abstract class BinaryDownloader {
|
|||||||
});
|
});
|
||||||
const total = Number(stream.headers.get("content-length"));
|
const total = Number(stream.headers.get("content-length"));
|
||||||
const bar = this.bar;
|
const bar = this.bar;
|
||||||
let fileHandle: FileHandle;
|
let fileHandle: FileHandle | undefined = undefined;
|
||||||
|
|
||||||
if (isNaN(total)) {
|
if (isNaN(total)) {
|
||||||
throw new Error("no content-length header was present");
|
throw new Error("no content-length header was present");
|
||||||
@ -66,7 +71,7 @@ abstract class BinaryDownloader {
|
|||||||
* This is necessary because for some reason `createWriteStream({ flags: "wx" })`
|
* This is necessary because for some reason `createWriteStream({ flags: "wx" })`
|
||||||
* was throwing someplace else and not here
|
* was throwing someplace else and not here
|
||||||
*/
|
*/
|
||||||
fileHandle = await open(this.target, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
|
const handle = fileHandle = await open(this.target, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
|
||||||
|
|
||||||
await pipeline(
|
await pipeline(
|
||||||
stream.body,
|
stream.body,
|
||||||
@ -79,7 +84,7 @@ abstract class BinaryDownloader {
|
|||||||
}),
|
}),
|
||||||
...this.getTransformStreams(new Writable({
|
...this.getTransformStreams(new Writable({
|
||||||
write(chunk, encoding, cb) {
|
write(chunk, encoding, cb) {
|
||||||
fileHandle.write(chunk)
|
handle.write(chunk)
|
||||||
.then(() => cb())
|
.then(() => cb())
|
||||||
.catch(cb);
|
.catch(cb);
|
||||||
},
|
},
|
||||||
@ -90,7 +95,7 @@ abstract class BinaryDownloader {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
await fileHandle?.close();
|
await fileHandle?.close();
|
||||||
|
|
||||||
if (error.code === "EEXIST") {
|
if (isErrnoException(error) && error.code === "EEXIST") {
|
||||||
bar.increment(total); // mark as finished
|
bar.increment(total); // mark as finished
|
||||||
controller.abort(); // stop trying to download
|
controller.abort(); // stop trying to download
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -9,8 +9,8 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
|
|||||||
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
|
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
|
||||||
import extensionsStoreInjectable from "../../extensions/extensions-store/extensions-store.injectable";
|
import extensionsStoreInjectable from "../../extensions/extensions-store/extensions-store.injectable";
|
||||||
import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store";
|
import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store";
|
||||||
import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||||
import type { FileSystemProvisionerStore } from "../../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store";
|
import type { FileSystemProvisionerStore } from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
|
||||||
import focusWindowInjectable from "../../renderer/ipc-channel-listeners/focus-window.injectable";
|
import focusWindowInjectable from "../../renderer/ipc-channel-listeners/focus-window.injectable";
|
||||||
|
|
||||||
// TODO: Make components free of side effects by making them deterministic
|
// TODO: Make components free of side effects by making them deterministic
|
||||||
|
|||||||
@ -2,20 +2,30 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { kubernetesClusterCategory } from "../kubernetes-cluster";
|
|
||||||
|
import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
|
||||||
|
import kubernetesClusterCategoryInjectable from "../../catalog/categories/kubernetes-cluster.injectable";
|
||||||
|
import type { KubernetesClusterCategory } from "../kubernetes-cluster";
|
||||||
|
|
||||||
|
|
||||||
describe("kubernetesClusterCategory", () => {
|
describe("kubernetesClusterCategory", () => {
|
||||||
|
let kubernetesClusterCategory: KubernetesClusterCategory;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const di = getDiForUnitTesting();
|
||||||
|
|
||||||
|
kubernetesClusterCategory = di.inject(kubernetesClusterCategoryInjectable);
|
||||||
|
});
|
||||||
|
|
||||||
describe("filteredItems", () => {
|
describe("filteredItems", () => {
|
||||||
const item1 = {
|
const item1 = {
|
||||||
icon: "Icon",
|
icon: "Icon",
|
||||||
title: "Title",
|
title: "Title",
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
onClick: () => {},
|
onClick: () => {},
|
||||||
};
|
};
|
||||||
const item2 = {
|
const item2 = {
|
||||||
icon: "Icon 2",
|
icon: "Icon 2",
|
||||||
title: "Title 2",
|
title: "Title 2",
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
onClick: () => {},
|
onClick: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import { WebLinkCategory } from "../catalog-entities";
|
|
||||||
import type { CatalogCategory } from "./catalog-entity";
|
import type { CatalogCategory } from "./catalog-entity";
|
||||||
import { CatalogCategoryRegistry } from "./category-registry";
|
import { CatalogCategoryRegistry } from "./category-registry";
|
||||||
|
|
||||||
@ -21,8 +20,6 @@ const catalogCategoryRegistryInjectable = getInjectable({
|
|||||||
registry.add(category);
|
registry.add(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.add(new WebLinkCategory());
|
|
||||||
|
|
||||||
return registry;
|
return registry;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { runInAction } from "mobx";
|
import { runInAction } from "mobx";
|
||||||
|
import { inspect } from "util";
|
||||||
import { isDefined } from "./type-narrowing";
|
import { isDefined } from "./type-narrowing";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,7 +80,7 @@ export async function getOrInsertWithAsync<K, V>(map: Map<K, V>, key: K, asyncBu
|
|||||||
*/
|
*/
|
||||||
export function strictSet<K, V>(map: Map<K, V>, key: K, val: V): typeof map {
|
export function strictSet<K, V>(map: Map<K, V>, key: K, val: V): typeof map {
|
||||||
if (map.has(key)) {
|
if (map.has(key)) {
|
||||||
throw new TypeError("Duplicate key in map");
|
throw new TypeError(`Map already contains key: ${inspect(key)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.set(key, val);
|
return map.set(key, val);
|
||||||
@ -92,7 +93,7 @@ export function strictSet<K, V>(map: Map<K, V>, key: K, val: V): typeof map {
|
|||||||
*/
|
*/
|
||||||
export function strictGet<K, V>(map: Map<K, V>, key: K): V {
|
export function strictGet<K, V>(map: Map<K, V>, key: K): V {
|
||||||
if (!map.has(key)) {
|
if (!map.has(key)) {
|
||||||
throw new TypeError("key not in map");
|
throw new TypeError(`Map does not contains key: ${inspect(key)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import type { InstalledExtension } from "../extension-discovery/extension-discovery";
|
||||||
|
import type { LensExtension, LensExtensionConstructor } from "../lens-extension";
|
||||||
|
|
||||||
|
export type CreateExtensionInstance = (ExtensionClass: LensExtensionConstructor, extension: InstalledExtension) => LensExtension;
|
||||||
|
|
||||||
|
export const createExtensionInstanceInjectionToken = getInjectionToken<CreateExtensionInstance>({
|
||||||
|
id: "create-extension-instance-token",
|
||||||
|
});
|
||||||
@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
|
||||||
import { createExtensionInstance } from "./create-extension-instance";
|
|
||||||
import fileSystemProvisionerStoreInjectable from "./file-system-provisioner-store/file-system-provisioner-store.injectable";
|
|
||||||
|
|
||||||
const createExtensionInstanceInjectable = getInjectable({
|
|
||||||
id: "create-extension-instance",
|
|
||||||
|
|
||||||
instantiate: (di) => createExtensionInstance({
|
|
||||||
fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createExtensionInstanceInjectable;
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import type { LensExtensionConstructor } from "../../lens-extension";
|
|
||||||
import type { InstalledExtension } from "../../extension-discovery/extension-discovery";
|
|
||||||
import type {
|
|
||||||
LensExtensionDependencies } from "../../lens-extension-set-dependencies";
|
|
||||||
import {
|
|
||||||
setLensExtensionDependencies,
|
|
||||||
} from "../../lens-extension-set-dependencies";
|
|
||||||
|
|
||||||
export const createExtensionInstance =
|
|
||||||
(dependencies: LensExtensionDependencies) =>
|
|
||||||
(ExtensionClass: LensExtensionConstructor, extension: InstalledExtension) => {
|
|
||||||
const instance = new ExtensionClass(extension);
|
|
||||||
|
|
||||||
instance[setLensExtensionDependencies](dependencies);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { observable } from "mobx";
|
||||||
|
import type { LensExtensionId, LensExtension } from "../lens-extension";
|
||||||
|
|
||||||
|
const extensionInstancesInjectable = getInjectable({
|
||||||
|
id: "extension-instances",
|
||||||
|
instantiate: () => observable.map<LensExtensionId, LensExtension>(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default extensionInstancesInjectable;
|
||||||
@ -5,20 +5,21 @@
|
|||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { ExtensionLoader } from "./extension-loader";
|
import { ExtensionLoader } from "./extension-loader";
|
||||||
import updateExtensionsStateInjectable from "./update-extensions-state/update-extensions-state.injectable";
|
import updateExtensionsStateInjectable from "./update-extensions-state/update-extensions-state.injectable";
|
||||||
import createExtensionInstanceInjectable from "./create-extension-instance/create-extension-instance.injectable";
|
|
||||||
import { extensionRegistratorInjectionToken } from "./extension-registrator-injection-token";
|
import { extensionRegistratorInjectionToken } from "./extension-registrator-injection-token";
|
||||||
import extensionInstallationCounterInjectable from "./extension-installation-counter.injectable";
|
import extensionInstallationCounterInjectable from "./extension-installation-counter.injectable";
|
||||||
|
import { createExtensionInstanceInjectionToken } from "./create-extension-instance.token";
|
||||||
|
import extensionInstancesInjectable from "./extension-instances.injectable";
|
||||||
|
|
||||||
const extensionLoaderInjectable = getInjectable({
|
const extensionLoaderInjectable = getInjectable({
|
||||||
id: "extension-loader",
|
id: "extension-loader",
|
||||||
|
|
||||||
instantiate: (di) =>
|
instantiate: (di) => new ExtensionLoader({
|
||||||
new ExtensionLoader({
|
updateExtensionsState: di.inject(updateExtensionsStateInjectable),
|
||||||
updateExtensionsState: di.inject(updateExtensionsStateInjectable),
|
createExtensionInstance: di.inject(createExtensionInstanceInjectionToken),
|
||||||
createExtensionInstance: di.inject(createExtensionInstanceInjectable),
|
extensionRegistrators: di.injectMany(extensionRegistratorInjectionToken),
|
||||||
extensionRegistrators: di.injectMany(extensionRegistratorInjectionToken),
|
extensionInstallationCounter: di.inject(extensionInstallationCounterInjectable),
|
||||||
extensionInstallationCounter: di.inject(extensionInstallationCounterInjectable),
|
extensionInstances: di.inject(extensionInstancesInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default extensionLoaderInjectable;
|
export default extensionLoaderInjectable;
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
import { EventEmitter } from "events";
|
|
||||||
import { isEqual } from "lodash";
|
import { isEqual } from "lodash";
|
||||||
|
import type { ObservableMap } from "mobx";
|
||||||
import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx";
|
import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc";
|
import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc";
|
||||||
@ -21,14 +21,17 @@ import type { LensExtensionState } from "../extensions-store/extensions-store";
|
|||||||
import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling";
|
import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling";
|
||||||
import { requestExtensionLoaderInitialState } from "../../renderer/ipc";
|
import { requestExtensionLoaderInitialState } from "../../renderer/ipc";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
|
import { EventEmitter } from "../../common/event-emitter";
|
||||||
|
import type { CreateExtensionInstance } from "./create-extension-instance.token";
|
||||||
|
|
||||||
const logModule = "[EXTENSIONS-LOADER]";
|
const logModule = "[EXTENSIONS-LOADER]";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
updateExtensionsState: (extensionsState: Record<LensExtensionId, LensExtensionState>) => void;
|
updateExtensionsState: (extensionsState: Record<LensExtensionId, LensExtensionState>) => void;
|
||||||
createExtensionInstance: (ExtensionClass: LensExtensionConstructor, extension: InstalledExtension) => LensExtension;
|
createExtensionInstance: CreateExtensionInstance;
|
||||||
extensionRegistrators: ((extension: LensExtension, extensionInstallationCount: number) => void)[];
|
readonly extensionRegistrators: ((extension: LensExtension, extensionInstallationCount: number) => void)[];
|
||||||
extensionInstallationCounter: Map<string, number>;
|
readonly extensionInstallationCounter: Map<string, number>;
|
||||||
|
readonly extensionInstances: ObservableMap<LensExtensionId, LensExtension>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionLoading {
|
export interface ExtensionLoading {
|
||||||
@ -40,23 +43,21 @@ export interface ExtensionLoading {
|
|||||||
* Loads installed extensions to the Lens application
|
* Loads installed extensions to the Lens application
|
||||||
*/
|
*/
|
||||||
export class ExtensionLoader {
|
export class ExtensionLoader {
|
||||||
protected extensions = observable.map<LensExtensionId, InstalledExtension>();
|
protected readonly extensions = observable.map<LensExtensionId, InstalledExtension>();
|
||||||
protected instances = observable.map<LensExtensionId, LensExtension>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the set of extensions that don't come with either
|
* This is the set of extensions that don't come with either
|
||||||
* - Main.LensExtension when running in the main process
|
* - Main.LensExtension when running in the main process
|
||||||
* - Renderer.LensExtension when running in the renderer process
|
* - Renderer.LensExtension when running in the renderer process
|
||||||
*/
|
*/
|
||||||
protected nonInstancesByName = observable.set<string>();
|
protected readonly nonInstancesByName = observable.set<string>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is updated by the `observe` in the constructor. DO NOT write directly to it
|
* This is updated by the `observe` in the constructor. DO NOT write directly to it
|
||||||
*/
|
*/
|
||||||
protected instancesByName = observable.map<string, LensExtension>();
|
protected readonly instancesByName = observable.map<string, LensExtension>();
|
||||||
|
|
||||||
// emits event "remove" of type LensExtension when the extension is removed
|
private readonly onRemoveExtensionId = new EventEmitter<[string]>();
|
||||||
private events = new EventEmitter();
|
|
||||||
|
|
||||||
@observable isLoaded = false;
|
@observable isLoaded = false;
|
||||||
|
|
||||||
@ -64,10 +65,10 @@ export class ExtensionLoader {
|
|||||||
return when(() => this.isLoaded);
|
return when(() => this.isLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(protected dependencies : Dependencies) {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
|
|
||||||
observe(this.instances, change => {
|
observe(this.dependencies.extensionInstances, change => {
|
||||||
switch (change.type) {
|
switch (change.type) {
|
||||||
case "add":
|
case "add":
|
||||||
if (this.instancesByName.has(change.newValue.name)) {
|
if (this.instancesByName.has(change.newValue.name)) {
|
||||||
@ -85,10 +86,6 @@ export class ExtensionLoader {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get enabledExtensionInstances() : LensExtension[] {
|
|
||||||
return [...this.instances.values()].filter(extension => extension.isEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed get userExtensions(): Map<LensExtensionId, InstalledExtension> {
|
@computed get userExtensions(): Map<LensExtensionId, InstalledExtension> {
|
||||||
const extensions = this.toJSON();
|
const extensions = this.toJSON();
|
||||||
|
|
||||||
@ -164,7 +161,7 @@ export class ExtensionLoader {
|
|||||||
@action
|
@action
|
||||||
removeInstance(lensExtensionId: LensExtensionId) {
|
removeInstance(lensExtensionId: LensExtensionId) {
|
||||||
logger.info(`${logModule} deleting extension instance ${lensExtensionId}`);
|
logger.info(`${logModule} deleting extension instance ${lensExtensionId}`);
|
||||||
const instance = this.instances.get(lensExtensionId);
|
const instance = this.dependencies.extensionInstances.get(lensExtensionId);
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
@ -172,8 +169,8 @@ export class ExtensionLoader {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
instance.disable();
|
instance.disable();
|
||||||
this.events.emit("remove", instance);
|
this.onRemoveExtensionId.emit(instance.id);
|
||||||
this.instances.delete(lensExtensionId);
|
this.dependencies.extensionInstances.delete(lensExtensionId);
|
||||||
this.nonInstancesByName.delete(instance.name);
|
this.nonInstancesByName.delete(instance.name);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`${logModule}: deactivation extension error`, { lensExtensionId, error });
|
logger.error(`${logModule}: deactivation extension error`, { lensExtensionId, error });
|
||||||
@ -260,8 +257,8 @@ export class ExtensionLoader {
|
|||||||
registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems),
|
registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems),
|
||||||
];
|
];
|
||||||
|
|
||||||
this.events.on("remove", (removedExtension: LensRendererExtension) => {
|
this.onRemoveExtensionId.addListener((removedExtensionId) => {
|
||||||
if (removedExtension.id === extension.id) {
|
if (removedExtensionId === extension.id) {
|
||||||
removeItems.forEach(remove => {
|
removeItems.forEach(remove => {
|
||||||
remove();
|
remove();
|
||||||
});
|
});
|
||||||
@ -288,8 +285,8 @@ export class ExtensionLoader {
|
|||||||
registries.KubeObjectDetailRegistry.getInstance().add(extension.kubeObjectDetailItems),
|
registries.KubeObjectDetailRegistry.getInstance().add(extension.kubeObjectDetailItems),
|
||||||
];
|
];
|
||||||
|
|
||||||
this.events.on("remove", (removedExtension: LensRendererExtension) => {
|
this.onRemoveExtensionId.addListener((removedExtensionId) => {
|
||||||
if (removedExtension.id === extension.id) {
|
if (removedExtensionId === extension.id) {
|
||||||
removeItems.forEach(remove => {
|
removeItems.forEach(remove => {
|
||||||
remove();
|
remove();
|
||||||
});
|
});
|
||||||
@ -309,7 +306,7 @@ export class ExtensionLoader {
|
|||||||
|
|
||||||
const extensions = [...installedExtensions.entries()]
|
const extensions = [...installedExtensions.entries()]
|
||||||
.map(([extId, extension]) => {
|
.map(([extId, extension]) => {
|
||||||
const alreadyInit = this.instances.has(extId) || this.nonInstancesByName.has(extension.manifest.name);
|
const alreadyInit = this.dependencies.extensionInstances.has(extId) || this.nonInstancesByName.has(extension.manifest.name);
|
||||||
|
|
||||||
if (extension.isCompatible && extension.isEnabled && !alreadyInit) {
|
if (extension.isCompatible && extension.isEnabled && !alreadyInit) {
|
||||||
try {
|
try {
|
||||||
@ -326,7 +323,7 @@ export class ExtensionLoader {
|
|||||||
extension,
|
extension,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.instances.set(extId, instance);
|
this.dependencies.extensionInstances.set(extId, instance);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instance,
|
instance,
|
||||||
@ -415,7 +412,7 @@ export class ExtensionLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getInstanceById(extId: LensExtensionId) {
|
getInstanceById(extId: LensExtensionId) {
|
||||||
return this.instances.get(extId);
|
return this.dependencies.extensionInstances.get(extId);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): Map<LensExtensionId, InstalledExtension> {
|
toJSON(): Map<LensExtensionId, InstalledExtension> {
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import directoryForUserDataInjectable from "../../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
import getAbsolutePathInjectable from "../../../../../common/path/get-absolute-path.injectable";
|
import getAbsolutePathInjectable from "../../../common/path/get-absolute-path.injectable";
|
||||||
|
|
||||||
const directoryForExtensionDataInjectable = getInjectable({
|
const directoryForExtensionDataInjectable = getInjectable({
|
||||||
id: "directory-for-extension-data",
|
id: "directory-for-extension-data",
|
||||||
@ -4,17 +4,18 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { FileSystemProvisionerStore } from "./file-system-provisioner-store";
|
import { FileSystemProvisionerStore } from "./file-system-provisioner-store";
|
||||||
import directoryForExtensionDataInjectable from "./directory-for-extension-data/directory-for-extension-data.injectable";
|
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
|
||||||
|
|
||||||
const fileSystemProvisionerStoreInjectable = getInjectable({
|
const fileSystemProvisionerStoreInjectable = getInjectable({
|
||||||
id: "file-system-provisioner-store",
|
id: "file-system-provisioner-store",
|
||||||
|
|
||||||
instantiate: (di) =>
|
instantiate: (di) => {
|
||||||
FileSystemProvisionerStore.createInstance({
|
FileSystemProvisionerStore.resetInstance();
|
||||||
directoryForExtensionData: di.inject(
|
|
||||||
directoryForExtensionDataInjectable,
|
return FileSystemProvisionerStore.createInstance({
|
||||||
),
|
directoryForExtensionData: di.inject(directoryForExtensionDataInjectable),
|
||||||
}),
|
});
|
||||||
|
},
|
||||||
|
|
||||||
causesSideEffects: true,
|
causesSideEffects: true,
|
||||||
});
|
});
|
||||||
@ -8,9 +8,9 @@ import { SHA256 } from "crypto-js";
|
|||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import { action, makeObservable, observable } from "mobx";
|
import { action, makeObservable, observable } from "mobx";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { BaseStore } from "../../../../common/base-store";
|
import { BaseStore } from "../../../common/base-store";
|
||||||
import type { LensExtensionId } from "../../../lens-extension";
|
import type { LensExtensionId } from "../../lens-extension";
|
||||||
import { getOrInsertWith, toJS } from "../../../../common/utils";
|
import { getOrInsertWith, toJS } from "../../../common/utils";
|
||||||
|
|
||||||
interface FSProvisionModel {
|
interface FSProvisionModel {
|
||||||
extensions: Record<string, string>; // extension names to paths
|
extensions: Record<string, string>; // extension names to paths
|
||||||
@ -4,15 +4,14 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import extensionLoaderInjectable from "./extension-loader/extension-loader.injectable";
|
import extensionInstancesInjectable from "./extension-loader/extension-instances.injectable";
|
||||||
|
|
||||||
const extensionsInjectable = getInjectable({
|
const extensionsInjectable = getInjectable({
|
||||||
id: "extensions",
|
id: "extensions",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const extensionLoader = di.inject(extensionLoaderInjectable);
|
const extensionInstances = di.inject(extensionInstancesInjectable);
|
||||||
|
|
||||||
return computed(() => extensionLoader.enabledExtensionInstances);
|
return computed(() => [...extensionInstances.values()].filter(extension => extension.isEnabled));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,12 +3,27 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { FileSystemProvisionerStore } from "./extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store";
|
import type { IComputedValue } from "mobx";
|
||||||
|
import type { CatalogCategoryRegistry } from "../common/catalog";
|
||||||
// This symbol encapsulates setting of dependencies to only happen locally in Lens Core
|
import type { NavigateToRoute } from "../common/front-end-routing/navigate-to-route-injection-token";
|
||||||
// and not by e.g. authors of extensions
|
import type { Route } from "../common/front-end-routing/route-injection-token";
|
||||||
export const setLensExtensionDependencies = Symbol("set-lens-extension-dependencies");
|
import type { CatalogEntityRegistry as MainCatalogEntityRegistry } from "../main/catalog";
|
||||||
|
import type { CatalogEntityRegistry as RendererCatalogEntityRegistry } from "../renderer/api/catalog/entity/registry";
|
||||||
|
import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable";
|
||||||
|
import type { FileSystemProvisionerStore } from "./extension-loader/file-system-provisioner-store/file-system-provisioner-store";
|
||||||
|
|
||||||
export interface LensExtensionDependencies {
|
export interface LensExtensionDependencies {
|
||||||
fileSystemProvisionerStore: FileSystemProvisionerStore;
|
readonly fileSystemProvisionerStore: FileSystemProvisionerStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LensMainExtensionDependencies extends LensExtensionDependencies {
|
||||||
|
readonly entityRegistry: MainCatalogEntityRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LensRendererExtensionDependencies extends LensExtensionDependencies {
|
||||||
|
navigateToRoute: NavigateToRoute;
|
||||||
|
getExtensionPageParameters: GetExtensionPageParameters;
|
||||||
|
readonly routes: IComputedValue<Route<unknown>[]>;
|
||||||
|
readonly entityRegistry: RendererCatalogEntityRegistry;
|
||||||
|
readonly categoryRegistry: CatalogCategoryRegistry;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,11 +10,7 @@ import type { ProtocolHandlerRegistration } from "./registries";
|
|||||||
import type { PackageJson } from "type-fest";
|
import type { PackageJson } from "type-fest";
|
||||||
import type { Disposer } from "../common/utils";
|
import type { Disposer } from "../common/utils";
|
||||||
import { disposer } from "../common/utils";
|
import { disposer } from "../common/utils";
|
||||||
import type {
|
import type { LensExtensionDependencies } from "./lens-extension-set-dependencies";
|
||||||
LensExtensionDependencies } from "./lens-extension-set-dependencies";
|
|
||||||
import {
|
|
||||||
setLensExtensionDependencies,
|
|
||||||
} from "./lens-extension-set-dependencies";
|
|
||||||
|
|
||||||
export type LensExtensionId = string; // path to manifest (package.json)
|
export type LensExtensionId = string; // path to manifest (package.json)
|
||||||
export type LensExtensionConstructor = new (...args: ConstructorParameters<typeof LensExtension>) => LensExtension;
|
export type LensExtensionConstructor = new (...args: ConstructorParameters<typeof LensExtension>) => LensExtension;
|
||||||
@ -28,7 +24,7 @@ export interface LensExtensionManifest extends PackageJson {
|
|||||||
|
|
||||||
export const Disposers = Symbol();
|
export const Disposers = Symbol();
|
||||||
|
|
||||||
export class LensExtension {
|
export class LensExtension<Dependencies extends LensExtensionDependencies = LensExtensionDependencies> {
|
||||||
readonly id: LensExtensionId;
|
readonly id: LensExtensionId;
|
||||||
readonly manifest: LensExtensionManifest;
|
readonly manifest: LensExtensionManifest;
|
||||||
readonly manifestPath: string;
|
readonly manifestPath: string;
|
||||||
@ -68,11 +64,7 @@ export class LensExtension {
|
|||||||
return this.manifest.description;
|
return this.manifest.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly dependencies!: LensExtensionDependencies;
|
protected readonly dependencies!: Dependencies;
|
||||||
|
|
||||||
[setLensExtensionDependencies] = (dependencies: LensExtensionDependencies) => {
|
|
||||||
(this as unknown as { dependencies: LensExtensionDependencies }).dependencies = dependencies;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getExtensionFileFolder returns the path to an already created folder. This
|
* getExtensionFileFolder returns the path to an already created folder. This
|
||||||
|
|||||||
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
import { LensExtension } from "./lens-extension";
|
import { LensExtension } from "./lens-extension";
|
||||||
import { WindowManager } from "../main/window-manager";
|
import { WindowManager } from "../main/window-manager";
|
||||||
import { catalogEntityRegistry } from "../main/catalog";
|
|
||||||
import type { CatalogEntity } from "../common/catalog";
|
import type { CatalogEntity } from "../common/catalog";
|
||||||
import type { IObservableArray } from "mobx";
|
import type { IObservableArray } from "mobx";
|
||||||
import type { MenuRegistration } from "../main/menu/menu-registration";
|
import type { MenuRegistration } from "../main/menu/menu-registration";
|
||||||
import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration";
|
import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration";
|
||||||
import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
|
import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
|
||||||
|
import type { LensMainExtensionDependencies } from "./lens-extension-set-dependencies";
|
||||||
|
|
||||||
export class LensMainExtension extends LensExtension {
|
export class LensMainExtension extends LensExtension<LensMainExtensionDependencies> {
|
||||||
appMenus: MenuRegistration[] = [];
|
appMenus: MenuRegistration[] = [];
|
||||||
trayMenus: TrayMenuRegistration[] = [];
|
trayMenus: TrayMenuRegistration[] = [];
|
||||||
|
|
||||||
@ -36,10 +36,10 @@ export class LensMainExtension extends LensExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addCatalogSource(id: string, source: IObservableArray<CatalogEntity>) {
|
addCatalogSource(id: string, source: IObservableArray<CatalogEntity>) {
|
||||||
catalogEntityRegistry.addObservableSource(`${this.name}:${id}`, source);
|
this.dependencies.entityRegistry.addObservableSource(`${this.name}:${id}`, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeCatalogSource(id: string) {
|
removeCatalogSource(id: string) {
|
||||||
catalogEntityRegistry.removeSource(`${this.name}:${id}`);
|
this.dependencies.entityRegistry.removeSource(`${this.name}:${id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,10 +7,8 @@ import type * as registries from "./registries";
|
|||||||
import { Disposers, LensExtension } from "./lens-extension";
|
import { Disposers, LensExtension } from "./lens-extension";
|
||||||
import type { CatalogEntity } from "../common/catalog";
|
import type { CatalogEntity } from "../common/catalog";
|
||||||
import type { Disposer } from "../common/utils";
|
import type { Disposer } from "../common/utils";
|
||||||
import type { EntityFilter } from "../renderer/api/catalog-entity-registry";
|
import type { EntityFilter } from "../renderer/api/catalog/entity/registry";
|
||||||
import { catalogEntityRegistry } from "../renderer/api/catalog-entity-registry";
|
|
||||||
import type { CategoryFilter } from "../renderer/api/catalog-category-registry";
|
import type { CategoryFilter } from "../renderer/api/catalog-category-registry";
|
||||||
import { catalogCategoryRegistry } from "../renderer/api/catalog-category-registry";
|
|
||||||
import type { TopBarRegistration } from "../renderer/components/layout/top-bar/top-bar-registration";
|
import type { TopBarRegistration } from "../renderer/components/layout/top-bar/top-bar-registration";
|
||||||
import type { KubernetesCluster } from "../common/catalog-entities";
|
import type { KubernetesCluster } from "../common/catalog-entities";
|
||||||
import type { WelcomeMenuRegistration } from "../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration";
|
import type { WelcomeMenuRegistration } from "../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration";
|
||||||
@ -23,15 +21,12 @@ import type { StatusBarRegistration } from "../renderer/components/status-bar/st
|
|||||||
import type { KubeObjectMenuRegistration } from "../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration";
|
import type { KubeObjectMenuRegistration } from "../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration";
|
||||||
import type { WorkloadsOverviewDetailRegistration } from "../renderer/components/+workloads-overview/workloads-overview-detail-registration";
|
import type { WorkloadsOverviewDetailRegistration } from "../renderer/components/+workloads-overview/workloads-overview-detail-registration";
|
||||||
import type { KubeObjectStatusRegistration } from "../renderer/components/kube-object-status-icon/kube-object-status-registration";
|
import type { KubeObjectStatusRegistration } from "../renderer/components/kube-object-status-icon/kube-object-status-registration";
|
||||||
import { Environments, getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
|
||||||
import routesInjectable from "../renderer/routes/routes.injectable";
|
|
||||||
import { fromPairs, map, matches, toPairs } from "lodash/fp";
|
import { fromPairs, map, matches, toPairs } from "lodash/fp";
|
||||||
import extensionPageParametersInjectable from "../renderer/routes/extension-page-parameters.injectable";
|
|
||||||
import { pipeline } from "@ogre-tools/fp";
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { navigateToRouteInjectionToken } from "../common/front-end-routing/navigate-to-route-injection-token";
|
|
||||||
import { getExtensionRoutePath } from "../renderer/routes/for-extension";
|
import { getExtensionRoutePath } from "../renderer/routes/for-extension";
|
||||||
|
import type { LensRendererExtensionDependencies } from "./lens-extension-set-dependencies";
|
||||||
|
|
||||||
export class LensRendererExtension extends LensExtension {
|
export class LensRendererExtension extends LensExtension<LensRendererExtensionDependencies> {
|
||||||
globalPages: registries.PageRegistration[] = [];
|
globalPages: registries.PageRegistration[] = [];
|
||||||
clusterPages: registries.PageRegistration[] = [];
|
clusterPages: registries.PageRegistration[] = [];
|
||||||
clusterPageMenus: registries.ClusterPageMenuRegistration[] = [];
|
clusterPageMenus: registries.ClusterPageMenuRegistration[] = [];
|
||||||
@ -51,9 +46,7 @@ export class LensRendererExtension extends LensExtension {
|
|||||||
customCategoryViews: CustomCategoryViewRegistration[] = [];
|
customCategoryViews: CustomCategoryViewRegistration[] = [];
|
||||||
|
|
||||||
async navigate(pageId?: string, params: object = {}) {
|
async navigate(pageId?: string, params: object = {}) {
|
||||||
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.renderer);
|
const routes = this.dependencies.routes.get();
|
||||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
|
||||||
const routes = di.inject(routesInjectable).get();
|
|
||||||
const targetRegistration = [...this.globalPages, ...this.clusterPages]
|
const targetRegistration = [...this.globalPages, ...this.clusterPages]
|
||||||
.find(registration => registration.id === (pageId || undefined));
|
.find(registration => registration.id === (pageId || undefined));
|
||||||
|
|
||||||
@ -68,7 +61,7 @@ export class LensRendererExtension extends LensExtension {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedParams = di.inject(extensionPageParametersInjectable, {
|
const normalizedParams = this.dependencies.getExtensionPageParameters({
|
||||||
extension: this,
|
extension: this,
|
||||||
registration: targetRegistration,
|
registration: targetRegistration,
|
||||||
});
|
});
|
||||||
@ -82,7 +75,7 @@ export class LensRendererExtension extends LensExtension {
|
|||||||
fromPairs,
|
fromPairs,
|
||||||
);
|
);
|
||||||
|
|
||||||
navigateToRoute(targetRoute, {
|
this.dependencies.navigateToRoute(targetRoute, {
|
||||||
query,
|
query,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -103,7 +96,7 @@ export class LensRendererExtension extends LensExtension {
|
|||||||
* @returns A function to clean up the filter
|
* @returns A function to clean up the filter
|
||||||
*/
|
*/
|
||||||
addCatalogFilter(fn: EntityFilter): Disposer {
|
addCatalogFilter(fn: EntityFilter): Disposer {
|
||||||
const dispose = catalogEntityRegistry.addCatalogFilter(fn);
|
const dispose = this.dependencies.entityRegistry.addCatalogFilter(fn);
|
||||||
|
|
||||||
this[Disposers].push(dispose);
|
this[Disposers].push(dispose);
|
||||||
|
|
||||||
@ -116,7 +109,7 @@ export class LensRendererExtension extends LensExtension {
|
|||||||
* @returns A function to clean up the filter
|
* @returns A function to clean up the filter
|
||||||
*/
|
*/
|
||||||
addCatalogCategoryFilter(fn: CategoryFilter): Disposer {
|
addCatalogCategoryFilter(fn: CategoryFilter): Disposer {
|
||||||
const dispose = catalogCategoryRegistry.addCatalogCategoryFilter(fn);
|
const dispose = this.dependencies.categoryRegistry.addCatalogCategoryFilter(fn);
|
||||||
|
|
||||||
this[Disposers].push(dispose);
|
this[Disposers].push(dispose);
|
||||||
|
|
||||||
|
|||||||
@ -5,24 +5,26 @@
|
|||||||
|
|
||||||
|
|
||||||
import type { CatalogCategory, CatalogEntity } from "../../common/catalog";
|
import type { CatalogCategory, CatalogEntity } from "../../common/catalog";
|
||||||
import { catalogEntityRegistry as registry } from "../../renderer/api/catalog-entity-registry";
|
import type { CatalogEntityOnBeforeRun } from "../../renderer/api/catalog/entity/registry";
|
||||||
import type { CatalogEntityOnBeforeRun } from "../../renderer/api/catalog-entity-registry";
|
|
||||||
import type { Disposer } from "../../common/utils";
|
import type { Disposer } from "../../common/utils";
|
||||||
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
|
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
|
||||||
import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||||
|
import catalogEntityRegistryInjectable from "../../renderer/api/catalog/entity/registry.injectable";
|
||||||
|
|
||||||
export const catalogCategories = asLegacyGlobalForExtensionApi(catalogCategoryRegistryInjectable);
|
export const catalogCategories = asLegacyGlobalForExtensionApi(catalogCategoryRegistryInjectable);
|
||||||
|
|
||||||
|
const internalEntityRegistry = asLegacyGlobalForExtensionApi(catalogEntityRegistryInjectable);
|
||||||
|
|
||||||
export class CatalogEntityRegistry {
|
export class CatalogEntityRegistry {
|
||||||
/**
|
/**
|
||||||
* Currently active/visible entity
|
* Currently active/visible entity
|
||||||
*/
|
*/
|
||||||
get activeEntity() {
|
get activeEntity() {
|
||||||
return registry.activeEntity;
|
return internalEntityRegistry.activeEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
get entities(): Map<string, CatalogEntity> {
|
get entities(): Map<string, CatalogEntity> {
|
||||||
return registry.entities;
|
return internalEntityRegistry.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(id: string) {
|
getById(id: string) {
|
||||||
@ -30,11 +32,11 @@ export class CatalogEntityRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||||
return registry.getItemsForApiKind<T>(apiVersion, kind);
|
return internalEntityRegistry.getItemsForApiKind<T>(apiVersion, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsForCategory<T extends CatalogEntity>(category: CatalogCategory): T[] {
|
getItemsForCategory<T extends CatalogEntity>(category: CatalogCategory): T[] {
|
||||||
return registry.getItemsForCategory(category);
|
return internalEntityRegistry.getItemsForCategory(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,7 +48,7 @@ export class CatalogEntityRegistry {
|
|||||||
* @returns A function to remove that hook
|
* @returns A function to remove that hook
|
||||||
*/
|
*/
|
||||||
addOnBeforeRun(onBeforeRun: CatalogEntityOnBeforeRun): Disposer {
|
addOnBeforeRun(onBeforeRun: CatalogEntityOnBeforeRun): Disposer {
|
||||||
return registry.addOnBeforeRun(onBeforeRun);
|
return internalEntityRegistry.addOnBeforeRun(onBeforeRun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token";
|
||||||
|
import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||||
|
import type { LensMainExtensionDependencies } from "../../extensions/lens-extension-set-dependencies";
|
||||||
|
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||||
|
|
||||||
|
const createExtensionInstanceInjectable = getInjectable({
|
||||||
|
id: "create-extension-instance",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const deps: LensMainExtensionDependencies = {
|
||||||
|
fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable),
|
||||||
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (ExtensionClass, extension) => {
|
||||||
|
const instance = new ExtensionClass(extension);
|
||||||
|
|
||||||
|
(instance as unknown as { dependencies: LensMainExtensionDependencies }).dependencies = deps;
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: createExtensionInstanceInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createExtensionInstanceInjectable;
|
||||||
@ -20,8 +20,8 @@ import loggerInjectable from "../common/logger.injectable";
|
|||||||
import spawnInjectable from "./child-process/spawn.injectable";
|
import spawnInjectable from "./child-process/spawn.injectable";
|
||||||
import extensionsStoreInjectable from "../extensions/extensions-store/extensions-store.injectable";
|
import extensionsStoreInjectable from "../extensions/extensions-store/extensions-store.injectable";
|
||||||
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
|
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
|
||||||
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||||
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store";
|
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
|
||||||
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
|
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
|
||||||
import type { ClusterStore } from "../common/cluster-store/cluster-store";
|
import type { ClusterStore } from "../common/cluster-store/cluster-store";
|
||||||
import type { Cluster } from "../common/cluster/cluster";
|
import type { Cluster } from "../common/cluster/cluster";
|
||||||
|
|||||||
@ -3,24 +3,19 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
|
||||||
import type { CatalogEntityData, CatalogEntityKindData } from "../catalog-entity";
|
|
||||||
import { CatalogCategory } from "../catalog-entity";
|
import { CatalogCategory } from "../catalog-entity";
|
||||||
import { KubernetesCluster, WebLink } from "../../../common/catalog-entities";
|
import { KubernetesCluster, WebLink } from "../../../common/catalog-entities";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import type { CatalogCategoryRegistry } from "../../../common/catalog";
|
import type { CatalogCategoryRegistry } from "../../../common/catalog";
|
||||||
import { categoryVersion } from "../../../common/catalog";
|
import { categoryVersion } from "../../../common/catalog";
|
||||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||||
|
import type { CatalogEntityRegistry } from "../catalog/entity/registry";
|
||||||
|
import catalogEntityRegistryInjectable from "../catalog/entity/registry.injectable";
|
||||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||||
|
|
||||||
class TestCatalogEntityRegistry extends CatalogEntityRegistry {
|
|
||||||
replaceItems(items: Array<CatalogEntityData & CatalogEntityKindData>) {
|
|
||||||
this.updateItems(items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FooBarCategory extends CatalogCategory {
|
class FooBarCategory extends CatalogCategory {
|
||||||
public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
|
public readonly apiVersion = "entityRegistry.k8slens.dev/v1alpha1";
|
||||||
public readonly kind = "CatalogCategory";
|
public readonly kind = "CatalogCategory";
|
||||||
public metadata = {
|
public metadata = {
|
||||||
name: "FooBars",
|
name: "FooBars",
|
||||||
@ -81,17 +76,18 @@ const entitykc = new KubernetesCluster({
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("CatalogEntityRegistry", () => {
|
describe("CatalogEntityRegistry", () => {
|
||||||
|
let entityRegistry: CatalogEntityRegistry;
|
||||||
let catalogCategoryRegistry: CatalogCategoryRegistry;
|
let catalogCategoryRegistry: CatalogCategoryRegistry;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const di = getDiForUnitTesting();
|
const di = getDiForUnitTesting();
|
||||||
|
|
||||||
|
entityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||||
catalogCategoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
catalogCategoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("updateItems", () => {
|
describe("updateItems", () => {
|
||||||
it("adds new catalog item", () => {
|
it("adds new catalog item", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
const items = [{
|
const items = [{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
kind: "KubernetesCluster",
|
kind: "KubernetesCluster",
|
||||||
@ -107,8 +103,8 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {},
|
spec: {},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(entityRegistry.items.get().length).toEqual(1);
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
@ -125,12 +121,11 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {},
|
spec: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.items.length).toEqual(2);
|
expect(entityRegistry.items.get().length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates existing items", () => {
|
it("updates existing items", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
const items = [{
|
const items = [{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
kind: "KubernetesCluster",
|
kind: "KubernetesCluster",
|
||||||
@ -146,19 +141,18 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {},
|
spec: {},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(entityRegistry.items.get().length).toEqual(1);
|
||||||
expect(catalog.items[0].status.phase).toEqual("disconnected");
|
expect(entityRegistry.items.get()[0].status.phase).toEqual("disconnected");
|
||||||
|
|
||||||
items[0].status.phase = "connected";
|
items[0].status.phase = "connected";
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(entityRegistry.items.get().length).toEqual(1);
|
||||||
expect(catalog.items[0].status.phase).toEqual("connected");
|
expect(entityRegistry.items.get()[0].status.phase).toEqual("connected");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates activeEntity", () => {
|
it("updates activeEntity", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
const items = [{
|
const items = [{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
kind: "KubernetesCluster",
|
kind: "KubernetesCluster",
|
||||||
@ -174,17 +168,16 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {},
|
spec: {},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
catalog.activeEntity = catalog.items[0];
|
entityRegistry.activeEntity = entityRegistry.items.get()[0];
|
||||||
expect(catalog.activeEntity.status.phase).toEqual("disconnected");
|
expect(entityRegistry.activeEntity.status.phase).toEqual("disconnected");
|
||||||
|
|
||||||
items[0].status.phase = "connected";
|
items[0].status.phase = "connected";
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.activeEntity.status.phase).toEqual("connected");
|
expect(entityRegistry.activeEntity.status.phase).toEqual("connected");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("removes deleted items", () => {
|
it("removes deleted items", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
@ -216,17 +209,16 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
items.splice(0, 1);
|
items.splice(0, 1);
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(entityRegistry.items.get().length).toEqual(1);
|
||||||
expect(catalog.items[0].metadata.uid).toEqual("456");
|
expect(entityRegistry.items.get()[0].metadata.uid).toEqual("456");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("items", () => {
|
describe("items", () => {
|
||||||
it("does not return items without matching category", () => {
|
it("does not return items without matching category", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
@ -258,13 +250,12 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
expect(catalog.items.length).toBe(1);
|
expect(entityRegistry.items.get().length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does return items after matching category is added", () => {
|
it("does return items after matching category is added", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
@ -282,29 +273,28 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
entityRegistry.updateItems(items);
|
||||||
catalogCategoryRegistry.add(new FooBarCategory());
|
catalogCategoryRegistry.add(new FooBarCategory());
|
||||||
expect(catalog.items.length).toBe(1);
|
expect(entityRegistry.items.get().length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not return items that are filtered out", () => {
|
it("does not return items that are filtered out", () => {
|
||||||
const source = observable.array([entity, entity2, entitykc]);
|
const source = observable.array([entity, entity2, entitykc]);
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
|
|
||||||
catalog.replaceItems(source);
|
entityRegistry.updateItems(source);
|
||||||
|
|
||||||
expect(catalog.items.length).toBe(3);
|
expect(entityRegistry.items.get().length).toBe(3);
|
||||||
expect(catalog.filteredItems.length).toBe(3);
|
expect(entityRegistry.filteredItems.length).toBe(3);
|
||||||
|
|
||||||
const d = catalog.addCatalogFilter(entity => entity.kind === KubernetesCluster.kind);
|
const d = entityRegistry.addCatalogFilter(entity => entity.kind === KubernetesCluster.kind);
|
||||||
|
|
||||||
expect(catalog.items.length).toBe(3);
|
expect(entityRegistry.items.get().length).toBe(3);
|
||||||
expect(catalog.filteredItems.length).toBe(1);
|
expect(entityRegistry.filteredItems.length).toBe(1);
|
||||||
|
|
||||||
// Remove filter
|
// Remove filter
|
||||||
d();
|
d();
|
||||||
|
|
||||||
expect(catalog.items.length).toBe(3);
|
expect(entityRegistry.items.get().length).toBe(3);
|
||||||
expect(catalog.filteredItems.length).toBe(3);
|
expect(entityRegistry.filteredItems.length).toBe(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,5 +3,9 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { catalogCategoryRegistry } from "../../common/catalog";
|
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
|
||||||
|
import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||||
|
|
||||||
export type { CategoryFilter } from "../../common/catalog";
|
export type { CategoryFilter } from "../../common/catalog";
|
||||||
|
|
||||||
|
export const catalogCategoryRegistry = asLegacyGlobalForExtensionApi(catalogCategoryRegistryInjectable);
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
|
||||||
import { catalogEntityRegistry } from "../catalog-entity-registry";
|
|
||||||
|
|
||||||
const catalogEntityRegistryInjectable = getInjectable({
|
|
||||||
id: "catalog-entity-registry",
|
|
||||||
instantiate: () => catalogEntityRegistry,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default catalogEntityRegistryInjectable;
|
|
||||||
@ -3,7 +3,6 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { catalogEntityRunContext } from "./catalog-entity-registry";
|
|
||||||
export { CatalogCategory, CatalogEntity } from "../../common/catalog";
|
export { CatalogCategory, CatalogEntity } from "../../common/catalog";
|
||||||
export type {
|
export type {
|
||||||
CatalogEntityData,
|
CatalogEntityData,
|
||||||
|
|||||||
18
src/renderer/api/catalog/entity/active.injectable.ts
Normal file
18
src/renderer/api/catalog/entity/active.injectable.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { computed } from "mobx";
|
||||||
|
import catalogEntityRegistryInjectable from "./registry.injectable";
|
||||||
|
|
||||||
|
const activeEntityInjectable = getInjectable({
|
||||||
|
id: "active-entity",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const registry = di.inject(catalogEntityRegistryInjectable);
|
||||||
|
|
||||||
|
return computed(() => registry.activeEntity);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default activeEntityInjectable;
|
||||||
13
src/renderer/api/catalog/entity/entities.injectable.ts
Normal file
13
src/renderer/api/catalog/entity/entities.injectable.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import catalogEntityRegistryInjectable from "./registry.injectable";
|
||||||
|
|
||||||
|
const catalogEnitiesInjectable = getInjectable({
|
||||||
|
id: "catalog-enities",
|
||||||
|
instantiate: (di) => di.inject(catalogEntityRegistryInjectable).items,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default catalogEnitiesInjectable;
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||||
|
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||||
|
import catalogEntityRegistryInjectable from "./registry.injectable";
|
||||||
|
|
||||||
|
export type GetActiveClusterEntity = () => Cluster | undefined;
|
||||||
|
|
||||||
|
const getActiveClusterEntityInjectable = getInjectable({
|
||||||
|
id: "get-active-cluster-entity",
|
||||||
|
instantiate: (di): GetActiveClusterEntity => {
|
||||||
|
const store = di.inject(clusterStoreInjectable);
|
||||||
|
const entityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||||
|
|
||||||
|
return () => store.getById(entityRegistry.activeEntity?.getId());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getActiveClusterEntityInjectable;
|
||||||
12
src/renderer/api/catalog/entity/legacy-globals.ts
Normal file
12
src/renderer/api/catalog/entity/legacy-globals.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { asLegacyGlobalFunctionForExtensionApi } from "../../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||||
|
import getActiveClusterEntityInjectable from "./get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `di.inject(getActiveClusterEntityInjectable)` instead
|
||||||
|
*/
|
||||||
|
export const getActiveClusterEntity = asLegacyGlobalFunctionForExtensionApi(getActiveClusterEntityInjectable);
|
||||||
18
src/renderer/api/catalog/entity/registry.injectable.ts
Normal file
18
src/renderer/api/catalog/entity/registry.injectable.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import catalogCategoryRegistryInjectable from "../../../../common/catalog/category-registry.injectable";
|
||||||
|
import navigateInjectable from "../../../navigation/navigate.injectable";
|
||||||
|
import { CatalogEntityRegistry } from "./registry";
|
||||||
|
|
||||||
|
const catalogEntityRegistryInjectable = getInjectable({
|
||||||
|
id: "catalog-entity-registry",
|
||||||
|
instantiate: (di) => new CatalogEntityRegistry({
|
||||||
|
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||||
|
navigate: di.inject(navigateInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default catalogEntityRegistryInjectable;
|
||||||
@ -4,57 +4,54 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { computed, observable, makeObservable, action } from "mobx";
|
import { computed, observable, makeObservable, action } from "mobx";
|
||||||
import { ipcRendererOn } from "../../common/ipc";
|
import { ipcRendererOn } from "../../../../common/ipc";
|
||||||
import type { CatalogCategory, CatalogEntity, CatalogEntityData, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog";
|
import type { CatalogCategory, CatalogEntity, CatalogEntityData, CatalogCategoryRegistry, CatalogEntityKindData } from "../../../../common/catalog";
|
||||||
import { catalogCategoryRegistry } from "../../common/catalog";
|
import "../../../../common/catalog-entities";
|
||||||
import "../../common/catalog-entities";
|
import { iter } from "../../../utils";
|
||||||
import type { Cluster } from "../../common/cluster/cluster";
|
import type { Disposer } from "../../../utils";
|
||||||
import { ClusterStore } from "../../common/cluster-store/cluster-store";
|
|
||||||
import { iter } from "../utils";
|
|
||||||
import type { Disposer } from "../utils";
|
|
||||||
import { once } from "lodash";
|
import { once } from "lodash";
|
||||||
import logger from "../../common/logger";
|
import logger from "../../../../common/logger";
|
||||||
import { CatalogRunEvent } from "../../common/catalog/catalog-run-event";
|
import { CatalogRunEvent } from "../../../../common/catalog/catalog-run-event";
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
import { catalogInitChannel, catalogItemsChannel, catalogEntityRunListener } from "../../common/ipc/catalog";
|
import { catalogInitChannel, catalogItemsChannel, catalogEntityRunListener } from "../../../../common/ipc/catalog";
|
||||||
import { navigate } from "../navigation";
|
|
||||||
import { isMainFrame } from "process";
|
import { isMainFrame } from "process";
|
||||||
|
import type { Navigate } from "../../../navigation/navigate.injectable";
|
||||||
|
|
||||||
export type EntityFilter = (entity: CatalogEntity) => any;
|
export type EntityFilter = (entity: CatalogEntity) => any;
|
||||||
export type CatalogEntityOnBeforeRun = (event: CatalogRunEvent) => void | Promise<void>;
|
export type CatalogEntityOnBeforeRun = (event: CatalogRunEvent) => void | Promise<void>;
|
||||||
|
|
||||||
export const catalogEntityRunContext = {
|
interface Dependencies {
|
||||||
navigate: (url: string) => navigate(url),
|
navigate: Navigate;
|
||||||
setCommandPaletteContext: (entity?: CatalogEntity) => {
|
readonly categoryRegistry: CatalogCategoryRegistry;
|
||||||
catalogEntityRegistry.activeEntity = entity;
|
}
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export class CatalogEntityRegistry {
|
export class CatalogEntityRegistry {
|
||||||
@observable protected activeEntityId: string | undefined = undefined;
|
protected readonly activeEntityId = observable.box<string | undefined>(undefined);
|
||||||
protected _entities = observable.map<string, CatalogEntity>([], { deep: true });
|
protected readonly _entities = observable.map<string, CatalogEntity>([], { deep: true });
|
||||||
protected filters = observable.set<EntityFilter>([], {
|
protected readonly filters = observable.set<EntityFilter>([], {
|
||||||
deep: false,
|
deep: false,
|
||||||
});
|
});
|
||||||
protected onBeforeRunHooks = observable.set<CatalogEntityOnBeforeRun>([], {
|
protected readonly onBeforeRunHooks = observable.set<CatalogEntityOnBeforeRun>([], {
|
||||||
deep: false,
|
deep: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer for keeping entities that don't yet have CatalogCategory synced
|
* Buffer for keeping entities that don't yet have CatalogCategory synced
|
||||||
*/
|
*/
|
||||||
protected rawEntities: (CatalogEntityData & CatalogEntityKindData)[] = [];
|
protected readonly rawEntities: (CatalogEntityData & CatalogEntityKindData)[] = [];
|
||||||
|
|
||||||
constructor(private categoryRegistry: CatalogCategoryRegistry) {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getActiveEntityById() {
|
protected getActiveEntityById() {
|
||||||
if (!this.activeEntityId) {
|
const activeEntityId = this.activeEntityId.get();
|
||||||
|
|
||||||
|
if (!activeEntityId) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._entities.get(this.activeEntityId);
|
return this._entities.get(activeEntityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeEntity(): CatalogEntity | undefined {
|
get activeEntity(): CatalogEntity | undefined {
|
||||||
@ -78,9 +75,9 @@ export class CatalogEntityRegistry {
|
|||||||
? raw
|
? raw
|
||||||
: raw.getId();
|
: raw.getId();
|
||||||
|
|
||||||
this.activeEntityId = id;
|
this.activeEntityId.set(id);
|
||||||
} else {
|
} else {
|
||||||
this.activeEntityId = undefined;
|
this.activeEntityId.set(undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +120,7 @@ export class CatalogEntityRegistry {
|
|||||||
const existing = this._entities.get(item.metadata.uid);
|
const existing = this._entities.get(item.metadata.uid);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
const entity = this.categoryRegistry.getEntityForData(item);
|
const entity = this.dependencies.categoryRegistry.getEntityForData(item);
|
||||||
|
|
||||||
if (entity) {
|
if (entity) {
|
||||||
this._entities.set(entity.getId(), entity);
|
this._entities.set(entity.getId(), entity);
|
||||||
@ -147,25 +144,25 @@ export class CatalogEntityRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get items() {
|
readonly items = computed(() => {
|
||||||
this.processRawEntities();
|
this.processRawEntities();
|
||||||
|
|
||||||
return Array.from(this._entities.values());
|
return Array.from(this._entities.values());
|
||||||
}
|
});
|
||||||
|
|
||||||
@computed get filteredItems() {
|
@computed get filteredItems() {
|
||||||
return Array.from(
|
return Array.from(
|
||||||
iter.reduce(
|
iter.reduce(
|
||||||
this.filters,
|
this.filters,
|
||||||
iter.filter,
|
iter.filter,
|
||||||
this.items.values(),
|
this.items.get().values(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get entities(): Map<string, CatalogEntity> {
|
@computed get entities(): Map<string, CatalogEntity> {
|
||||||
return new Map(
|
return new Map(
|
||||||
this.items.map(entity => [entity.getId(), entity]),
|
this.items.get().map(entity => [entity.getId(), entity]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,13 +172,13 @@ export class CatalogEntityRegistry {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getById<T extends CatalogEntity>(id: string) {
|
getById(id: string) {
|
||||||
return this.entities.get(id) as T;
|
return this.entities.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string, { filtered = false } = {}): T[] {
|
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string, { filtered = false } = {}): T[] {
|
||||||
const byApiKind = (item: CatalogEntity) => item.apiVersion === apiVersion && item.kind === kind;
|
const byApiKind = (item: CatalogEntity) => item.apiVersion === apiVersion && item.kind === kind;
|
||||||
const entities = filtered ? this.filteredItems : this.items;
|
const entities = filtered ? this.filteredItems : this.items.get();
|
||||||
|
|
||||||
return entities.filter(byApiKind) as T[];
|
return entities.filter(byApiKind) as T[];
|
||||||
}
|
}
|
||||||
@ -189,7 +186,7 @@ export class CatalogEntityRegistry {
|
|||||||
getItemsForCategory<T extends CatalogEntity>(category: CatalogCategory, { filtered = false } = {}): T[] {
|
getItemsForCategory<T extends CatalogEntity>(category: CatalogCategory, { filtered = false } = {}): T[] {
|
||||||
const supportedVersions = new Set(category.spec.versions.map((v) => `${category.spec.group}/${v.name}`));
|
const supportedVersions = new Set(category.spec.versions.map((v) => `${category.spec.group}/${v.name}`));
|
||||||
const byApiVersionKind = (item: CatalogEntity) => supportedVersions.has(item.apiVersion) && item.kind === category.spec.names.kind;
|
const byApiVersionKind = (item: CatalogEntity) => supportedVersions.has(item.apiVersion) && item.kind === category.spec.names.kind;
|
||||||
const entities = filtered ? this.filteredItems : this.items;
|
const entities = filtered ? this.filteredItems : this.items.get();
|
||||||
|
|
||||||
return entities.filter(byApiVersionKind) as T[];
|
return entities.filter(byApiVersionKind) as T[];
|
||||||
}
|
}
|
||||||
@ -249,7 +246,12 @@ export class CatalogEntityRegistry {
|
|||||||
this.onBeforeRun(entity)
|
this.onBeforeRun(entity)
|
||||||
.then(doOnRun => {
|
.then(doOnRun => {
|
||||||
if (doOnRun) {
|
if (doOnRun) {
|
||||||
return entity.onRun?.(catalogEntityRunContext);
|
return entity.onRun?.({
|
||||||
|
navigate: this.dependencies.navigate,
|
||||||
|
setCommandPaletteContext: (entity) => {
|
||||||
|
this.activeEntity = entity;
|
||||||
|
},
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`onBeforeRun for ${entity.getId()} returned false`);
|
logger.debug(`onBeforeRun for ${entity.getId()} returned false`);
|
||||||
}
|
}
|
||||||
@ -257,9 +259,3 @@ export class CatalogEntityRegistry {
|
|||||||
.catch(error => logger.error(`[CATALOG-ENTITY-REGISTRY]: entity ${entity.getId()} onRun threw an error`, error));
|
.catch(error => logger.error(`[CATALOG-ENTITY-REGISTRY]: entity ${entity.getId()} onRun threw an error`, error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
|
|
||||||
export function getActiveClusterEntity(): Cluster | undefined {
|
|
||||||
return ClusterStore.getInstance().getById(catalogEntityRegistry.activeEntity?.getId());
|
|
||||||
}
|
|
||||||
@ -9,7 +9,7 @@ import isActiveRouteInjectable from "../../navigation/is-route-active.injectable
|
|||||||
import observableHistoryInjectable from "../../navigation/observable-history.injectable";
|
import observableHistoryInjectable from "../../navigation/observable-history.injectable";
|
||||||
import type { Disposer } from "../../utils";
|
import type { Disposer } from "../../utils";
|
||||||
import { disposer } from "../../utils";
|
import { disposer } from "../../utils";
|
||||||
import catalogEntityRegistryInjectable from "../catalog-entity-registry/catalog-entity-registry.injectable";
|
import catalogEntityRegistryInjectable from "../catalog/entity/registry.injectable";
|
||||||
|
|
||||||
export type WatchForGeneralEntityNavigation = () => Disposer;
|
export type WatchForGeneralEntityNavigation = () => Disposer;
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,8 @@ import rendererExtensionsInjectable from "../../../../extensions/renderer-extens
|
|||||||
import { CatalogCategory } from "../../../api/catalog-entity";
|
import { CatalogCategory } from "../../../api/catalog-entity";
|
||||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||||
import type { AdditionalCategoryColumnRegistration, CategoryColumnRegistration } from "../custom-category-columns";
|
import type { AdditionalCategoryColumnRegistration, CategoryColumnRegistration } from "../custom-category-columns";
|
||||||
import type { CategoryColumns, GetCategoryColumnsParams } from "../get-category-columns.injectable";
|
import type { CategoryColumns, GetCategoryColumnsParams } from "../columns/get.injectable";
|
||||||
import getCategoryColumnsInjectable from "../get-category-columns.injectable";
|
import getCategoryColumnsInjectable from "../columns/get.injectable";
|
||||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||||
|
|
||||||
class TestCategory extends CatalogCategory {
|
class TestCategory extends CatalogCategory {
|
||||||
|
|||||||
@ -14,16 +14,22 @@ import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
|||||||
import { isDevelopment } from "../../../common/vars";
|
import { isDevelopment } from "../../../common/vars";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { Avatar } from "../avatar";
|
import { Avatar } from "../avatar";
|
||||||
import { getLabelBadges } from "./helpers";
|
import type { GetLabelBadges } from "./get-label-badges.injectable";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import getLabelBadgesInjectable from "./get-label-badges.injectable";
|
||||||
|
|
||||||
export interface CatalogEntityDetailsProps<T extends CatalogEntity> {
|
export interface CatalogEntityDetailsProps<Entity extends CatalogEntity> {
|
||||||
entity: T;
|
entity: Entity;
|
||||||
hideDetails(): void;
|
hideDetails(): void;
|
||||||
onRun: () => void;
|
onRun: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
getLabelBadges: GetLabelBadges;
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class CatalogEntityDetails<T extends CatalogEntity> extends Component<CatalogEntityDetailsProps<T>> {
|
class NonInjectedCatalogEntityDetails<Entity extends CatalogEntity> extends Component<CatalogEntityDetailsProps<Entity> & Dependencies> {
|
||||||
categoryIcon(category: CatalogCategory) {
|
categoryIcon(category: CatalogCategory) {
|
||||||
if (Icon.isSvg(category.metadata.icon)) {
|
if (Icon.isSvg(category.metadata.icon)) {
|
||||||
return <Icon svg={category.metadata.icon} smallest />;
|
return <Icon svg={category.metadata.icon} smallest />;
|
||||||
@ -32,8 +38,8 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Cat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContent(entity: T) {
|
renderContent(entity: Entity) {
|
||||||
const { onRun, hideDetails } = this.props;
|
const { onRun, hideDetails, getLabelBadges } = this.props;
|
||||||
const detailItems = CatalogEntityDetailRegistry.getInstance().getItemsForKind(entity.kind, entity.apiVersion);
|
const detailItems = CatalogEntityDetailRegistry.getInstance().getItemsForKind(entity.kind, entity.apiVersion);
|
||||||
const details = detailItems.map(({ components }, index) => <components.Details entity={entity} key={index} />);
|
const details = detailItems.map(({ components }, index) => <components.Details entity={entity} key={index} />);
|
||||||
const showDefaultDetails = detailItems.find((item) => item.priority ?? 50 > 999) === undefined;
|
const showDefaultDetails = detailItems.find((item) => item.priority ?? 50 > 999) === undefined;
|
||||||
@ -109,3 +115,10 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Cat
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CatalogEntityDetails = withInjectables<Dependencies, CatalogEntityDetailsProps<CatalogEntity>>(NonInjectedCatalogEntityDetails, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
getLabelBadges: di.inject(getLabelBadgesInjectable),
|
||||||
|
}),
|
||||||
|
}) as <Entity extends CatalogEntity>(props: CatalogEntityDetailsProps<Entity>) => React.ReactElement;
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { catalogEntityStore } from "./catalog-entity.store";
|
import { catalogEntityStore } from "./catalog-entity.store";
|
||||||
import catalogEntityRegistryInjectable from "../../../api/catalog-entity-registry/catalog-entity-registry.injectable";
|
import catalogEntityRegistryInjectable from "../../../api/catalog/entity/registry.injectable";
|
||||||
import catalogCategoryRegistryInjectable from "../../../../common/catalog/category-registry.injectable";
|
import catalogCategoryRegistryInjectable from "../../../../common/catalog/category-registry.injectable";
|
||||||
|
|
||||||
const catalogEntityStoreInjectable = getInjectable({
|
const catalogEntityStoreInjectable = getInjectable({
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import type { IComputedValue, IObservableValue } from "mobx";
|
import type { IComputedValue, IObservableValue } from "mobx";
|
||||||
import { computed, observable, reaction } from "mobx";
|
import { computed, observable, reaction } from "mobx";
|
||||||
import type { CatalogEntityRegistry } from "../../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
|
||||||
import type { CatalogEntity } from "../../../api/catalog-entity";
|
import type { CatalogEntity } from "../../../api/catalog-entity";
|
||||||
import type { CatalogCategory, CatalogCategoryRegistry } from "../../../../common/catalog";
|
import type { CatalogCategory, CatalogCategoryRegistry } from "../../../../common/catalog";
|
||||||
import type { Disposer } from "../../../../common/utils";
|
import type { Disposer } from "../../../../common/utils";
|
||||||
|
|||||||
@ -9,14 +9,14 @@ import userEvent from "@testing-library/user-event";
|
|||||||
import { Catalog } from "./catalog";
|
import { Catalog } from "./catalog";
|
||||||
import { mockWindow } from "../../../../__mocks__/windowMock";
|
import { mockWindow } from "../../../../__mocks__/windowMock";
|
||||||
import type { CatalogEntityActionContext, CatalogEntityData } from "../../../common/catalog";
|
import type { CatalogEntityActionContext, CatalogEntityData } from "../../../common/catalog";
|
||||||
import { CatalogCategoryRegistry, CatalogEntity } from "../../../common/catalog";
|
import { CatalogEntity } from "../../../common/catalog";
|
||||||
import { CatalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||||
import type { CatalogEntityStore } from "./catalog-entity-store/catalog-entity.store";
|
import type { CatalogEntityStore } from "./catalog-entity-store/catalog-entity.store";
|
||||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
import type { DiContainer } from "@ogre-tools/injectable";
|
||||||
import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-store.injectable";
|
import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-store.injectable";
|
||||||
import catalogEntityRegistryInjectable from "../../api/catalog-entity-registry/catalog-entity-registry.injectable";
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
import type { DiRender } from "../test-utils/renderFor";
|
import type { DiRender } from "../test-utils/renderFor";
|
||||||
import { renderFor } from "../test-utils/renderFor";
|
import { renderFor } from "../test-utils/renderFor";
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
@ -101,10 +101,7 @@ describe("<Catalog />", () => {
|
|||||||
render = renderFor(di);
|
render = renderFor(di);
|
||||||
onRun = jest.fn();
|
onRun = jest.fn();
|
||||||
catalogEntityItem = createMockCatalogEntity(onRun);
|
catalogEntityItem = createMockCatalogEntity(onRun);
|
||||||
|
catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||||
const catalogCategoryRegistry = new CatalogCategoryRegistry();
|
|
||||||
|
|
||||||
catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
|
|
||||||
|
|
||||||
di.override(catalogEntityRegistryInjectable, () => catalogEntityRegistry);
|
di.override(catalogEntityRegistryInjectable, () => catalogEntityRegistry);
|
||||||
|
|
||||||
|
|||||||
@ -30,8 +30,8 @@ import { Avatar } from "../avatar";
|
|||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import catalogPreviousActiveTabStorageInjectable from "./catalog-previous-active-tab-storage/catalog-previous-active-tab-storage.injectable";
|
import catalogPreviousActiveTabStorageInjectable from "./catalog-previous-active-tab-storage/catalog-previous-active-tab-storage.injectable";
|
||||||
import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-store.injectable";
|
import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-store.injectable";
|
||||||
import type { GetCategoryColumnsParams, CategoryColumns } from "./get-category-columns.injectable";
|
import type { GetCategoryColumnsParams, CategoryColumns } from "./columns/get.injectable";
|
||||||
import getCategoryColumnsInjectable from "./get-category-columns.injectable";
|
import getCategoryColumnsInjectable from "./columns/get.injectable";
|
||||||
import type { RegisteredCustomCategoryViewDecl } from "./custom-views.injectable";
|
import type { RegisteredCustomCategoryViewDecl } from "./custom-views.injectable";
|
||||||
import customCategoryViewsInjectable from "./custom-views.injectable";
|
import customCategoryViewsInjectable from "./custom-views.injectable";
|
||||||
import type { CustomCategoryViewComponents } from "./custom-views";
|
import type { CustomCategoryViewComponents } from "./custom-views";
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import namedCategoryColumnInjectable from "./named-category.injectable";
|
||||||
|
import defaultCategoryColumnsInjectable from "./default-category.injectable";
|
||||||
|
|
||||||
|
const defaultBrowseAllColumns: RegisteredAdditionalCategoryColumn[] = [
|
||||||
|
{
|
||||||
|
id: "kind",
|
||||||
|
priority: 5,
|
||||||
|
renderCell: entity => entity.kind,
|
||||||
|
titleProps: {
|
||||||
|
id: "kind",
|
||||||
|
sortBy: "kind",
|
||||||
|
title: "Kind",
|
||||||
|
},
|
||||||
|
sortCallback: entity => entity.kind,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const browseAllColumnsInjectable = getInjectable({
|
||||||
|
id: "browse-all-columns",
|
||||||
|
instantiate: (di) => [
|
||||||
|
...defaultBrowseAllColumns,
|
||||||
|
di.inject(namedCategoryColumnInjectable),
|
||||||
|
...di.inject(defaultCategoryColumnsInjectable),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default browseAllColumnsInjectable;
|
||||||
|
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import styles from "../catalog.module.scss";
|
||||||
|
import React from "react";
|
||||||
|
import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns";
|
||||||
|
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import getLabelBadgesInjectable from "../get-label-badges.injectable";
|
||||||
|
|
||||||
|
const defaultCategoryColumnsInjectable = getInjectable({
|
||||||
|
id: "default-category-columns",
|
||||||
|
instantiate: (di): RegisteredAdditionalCategoryColumn[] => {
|
||||||
|
const getLabelBadges = di.inject(getLabelBadgesInjectable);
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: "source",
|
||||||
|
priority: 10,
|
||||||
|
renderCell: entity => entity.getSource(),
|
||||||
|
titleProps: {
|
||||||
|
title: "Source",
|
||||||
|
className: styles.sourceCell,
|
||||||
|
id: "source",
|
||||||
|
sortBy: "source",
|
||||||
|
},
|
||||||
|
sortCallback: entity => entity.getSource(),
|
||||||
|
searchFilter: entity => `source=${entity.getSource()}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "labels",
|
||||||
|
priority: 20,
|
||||||
|
renderCell: getLabelBadges,
|
||||||
|
titleProps: {
|
||||||
|
id: "labels",
|
||||||
|
title: "Labels",
|
||||||
|
className: `${styles.labelsCell} scrollable`,
|
||||||
|
},
|
||||||
|
searchFilter: entity => KubeObject.stringifyLabels(entity.metadata.labels),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "status",
|
||||||
|
priority: 30,
|
||||||
|
renderCell: entity => (
|
||||||
|
<span key="phase" className={entity.status.phase}>
|
||||||
|
{entity.status.phase}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
titleProps: {
|
||||||
|
title: "Status",
|
||||||
|
className: styles.statusCell,
|
||||||
|
id: "status",
|
||||||
|
sortBy: "status",
|
||||||
|
},
|
||||||
|
searchFilter: entity => entity.status.phase,
|
||||||
|
sortCallback: entity => entity.status.phase,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default defaultCategoryColumnsInjectable;
|
||||||
63
src/renderer/components/+catalog/columns/get.injectable.ts
Normal file
63
src/renderer/components/+catalog/columns/get.injectable.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { orderBy } from "lodash";
|
||||||
|
import type { CatalogCategory, CatalogEntity } from "../../../../common/catalog";
|
||||||
|
import type { ItemListLayoutProps } from "../../item-object-list";
|
||||||
|
import browseAllColumnsInjectable from "./browse-all.injectable";
|
||||||
|
import getColumnsForCategoryInjectable from "./specific-category.injectable";
|
||||||
|
|
||||||
|
export interface GetCategoryColumnsParams {
|
||||||
|
activeCategory: CatalogCategory | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CategoryColumns = Required<Pick<ItemListLayoutProps<CatalogEntity>, "sortingCallbacks" | "searchFilters" | "renderTableContents" | "renderTableHeader">>;
|
||||||
|
export type GetCategoryColumns = (params: GetCategoryColumnsParams) => CategoryColumns;
|
||||||
|
|
||||||
|
const getCategoryColumnsInjectable = getInjectable({
|
||||||
|
id: "get-category-columns",
|
||||||
|
|
||||||
|
instantiate: (di): GetCategoryColumns => {
|
||||||
|
const getColumnsForCategory = di.inject(getColumnsForCategoryInjectable);
|
||||||
|
const browseAllColumns = di.inject(browseAllColumnsInjectable);
|
||||||
|
|
||||||
|
return ({ activeCategory }) => {
|
||||||
|
const allRegistrations = orderBy(
|
||||||
|
activeCategory
|
||||||
|
? getColumnsForCategory(activeCategory)
|
||||||
|
: browseAllColumns,
|
||||||
|
"priority",
|
||||||
|
"asc",
|
||||||
|
);
|
||||||
|
|
||||||
|
const sortingCallbacks: CategoryColumns["sortingCallbacks"] = {};
|
||||||
|
const searchFilters: CategoryColumns["searchFilters"] = [];
|
||||||
|
const renderTableHeader: CategoryColumns["renderTableHeader"] = [];
|
||||||
|
const tableRowRenderers: ((entity: CatalogEntity) => React.ReactNode)[] = [];
|
||||||
|
|
||||||
|
for (const registration of allRegistrations) {
|
||||||
|
if (registration.sortCallback) {
|
||||||
|
sortingCallbacks[registration.id] = registration.sortCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registration.searchFilter) {
|
||||||
|
searchFilters.push(registration.searchFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
tableRowRenderers.push(registration.renderCell);
|
||||||
|
renderTableHeader.push(registration.titleProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sortingCallbacks,
|
||||||
|
renderTableHeader,
|
||||||
|
renderTableContents: entity => tableRowRenderers.map(fn => fn(entity)),
|
||||||
|
searchFilters,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getCategoryColumnsInjectable;
|
||||||
@ -3,15 +3,15 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import styles from "./catalog.module.scss";
|
import styles from "../catalog.module.scss";
|
||||||
import type { CatalogEntity } from "../../../common/catalog";
|
import type { CatalogEntity } from "../../../../common/catalog";
|
||||||
import { prevDefault } from "../../utils";
|
import { prevDefault } from "../../../utils";
|
||||||
import { Avatar } from "../avatar";
|
import { Avatar } from "../../avatar";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../../icon";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { RegisteredAdditionalCategoryColumn } from "./custom-category-columns";
|
import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns";
|
||||||
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
|
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||||
import type { HotbarStore } from "../../../common/hotbars/store";
|
import type { HotbarStore } from "../../../../common/hotbars/store";
|
||||||
|
|
||||||
const renderEntityName = (hotbarStore: HotbarStore) => (entity: CatalogEntity) => {
|
const renderEntityName = (hotbarStore: HotbarStore) => (entity: CatalogEntity) => {
|
||||||
const isItemInHotbar = hotbarStore.isAddedToActive(entity);
|
const isItemInHotbar = hotbarStore.isAddedToActive(entity);
|
||||||
@ -45,8 +45,7 @@ const renderEntityName = (hotbarStore: HotbarStore) => (entity: CatalogEntity) =
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const namedCategoryColumnInjectable = getInjectable({
|
||||||
const nameCategoryColumnInjectable = getInjectable({
|
|
||||||
id: "name-category-column",
|
id: "name-category-column",
|
||||||
instantiate: (di): RegisteredAdditionalCategoryColumn => ({
|
instantiate: (di): RegisteredAdditionalCategoryColumn => ({
|
||||||
id: "name",
|
id: "name",
|
||||||
@ -63,4 +62,4 @@ const nameCategoryColumnInjectable = getInjectable({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default nameCategoryColumnInjectable;
|
export default namedCategoryColumnInjectable;
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type { CatalogCategory } from "../../../api/catalog-entity";
|
||||||
|
import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns";
|
||||||
|
import categoryColumnsInjectable from "../custom-category-columns.injectable";
|
||||||
|
import defaultCategoryColumnsInjectable from "./default-category.injectable";
|
||||||
|
import namedCategoryColumnInjectable from "./named-category.injectable";
|
||||||
|
|
||||||
|
export type GetColumnsForCategory = (activeCategory: CatalogCategory) => RegisteredAdditionalCategoryColumn[];
|
||||||
|
|
||||||
|
const getColumnsForCategoryInjectable = getInjectable({
|
||||||
|
id: "get-columns-for-category",
|
||||||
|
instantiate: (di): GetColumnsForCategory => {
|
||||||
|
const extensionColumns = di.inject(categoryColumnsInjectable);
|
||||||
|
const defaultCategoryColumns = di.inject(defaultCategoryColumnsInjectable);
|
||||||
|
const nameCategoryColumn = di.inject(namedCategoryColumnInjectable);
|
||||||
|
|
||||||
|
return (activeCategory) => {
|
||||||
|
const fromExtensions = (
|
||||||
|
extensionColumns
|
||||||
|
.get()
|
||||||
|
.get(activeCategory.spec.group)
|
||||||
|
?.get(activeCategory.spec.names.kind)
|
||||||
|
?? []
|
||||||
|
);
|
||||||
|
const fromCategory = activeCategory.spec.displayColumns?.map(({ priority = 50, ...column }) => ({
|
||||||
|
priority,
|
||||||
|
...column,
|
||||||
|
})) ?? defaultCategoryColumns;
|
||||||
|
|
||||||
|
return [
|
||||||
|
nameCategoryColumn,
|
||||||
|
...fromExtensions,
|
||||||
|
...fromCategory,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getColumnsForCategoryInjectable;
|
||||||
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
|
||||||
import { orderBy } from "lodash";
|
|
||||||
import type { IComputedValue } from "mobx";
|
|
||||||
import type { CatalogCategory, CatalogEntity } from "../../../common/catalog";
|
|
||||||
import type { ItemListLayoutProps } from "../item-object-list";
|
|
||||||
import type { RegisteredAdditionalCategoryColumn } from "./custom-category-columns";
|
|
||||||
import categoryColumnsInjectable from "./custom-category-columns.injectable";
|
|
||||||
import { defaultCategoryColumns, browseAllColumns } from "./internal-category-columns";
|
|
||||||
import nameCategoryColumnInjectable from "./name-category-column.injectable";
|
|
||||||
|
|
||||||
interface Dependencies {
|
|
||||||
extensionColumns: IComputedValue<Map<string, Map<string, RegisteredAdditionalCategoryColumn[]>>>;
|
|
||||||
nameCategoryColumn: RegisteredAdditionalCategoryColumn;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GetCategoryColumnsParams {
|
|
||||||
activeCategory: CatalogCategory | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CategoryColumns = Required<Pick<ItemListLayoutProps<CatalogEntity>, "sortingCallbacks" | "searchFilters" | "renderTableContents" | "renderTableHeader">>;
|
|
||||||
|
|
||||||
function getSpecificCategoryColumns(activeCategory: CatalogCategory, extensionColumns: IComputedValue<Map<string, Map<string, RegisteredAdditionalCategoryColumn[]>>>, nameCategoryColumn: RegisteredAdditionalCategoryColumn): RegisteredAdditionalCategoryColumn[] {
|
|
||||||
const fromExtensions = (
|
|
||||||
extensionColumns
|
|
||||||
.get()
|
|
||||||
.get(activeCategory.spec.group)
|
|
||||||
?.get(activeCategory.spec.names.kind)
|
|
||||||
?? []
|
|
||||||
);
|
|
||||||
const fromCategory = activeCategory.spec.displayColumns?.map(({ priority = 50, ...column }) => ({
|
|
||||||
priority,
|
|
||||||
...column,
|
|
||||||
})) ?? defaultCategoryColumns;
|
|
||||||
|
|
||||||
return [
|
|
||||||
nameCategoryColumn,
|
|
||||||
...fromExtensions,
|
|
||||||
...fromCategory,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBrowseAllColumns(nameCategoryColumn: RegisteredAdditionalCategoryColumn): RegisteredAdditionalCategoryColumn[] {
|
|
||||||
return [
|
|
||||||
...browseAllColumns,
|
|
||||||
nameCategoryColumn,
|
|
||||||
...defaultCategoryColumns,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCategoryColumns = ({ extensionColumns, nameCategoryColumn }: Dependencies) => ({ activeCategory }: GetCategoryColumnsParams): CategoryColumns => {
|
|
||||||
const allRegistrations = orderBy(
|
|
||||||
activeCategory
|
|
||||||
? getSpecificCategoryColumns(activeCategory, extensionColumns, nameCategoryColumn)
|
|
||||||
: getBrowseAllColumns(nameCategoryColumn),
|
|
||||||
"priority",
|
|
||||||
"asc",
|
|
||||||
);
|
|
||||||
|
|
||||||
const sortingCallbacks: CategoryColumns["sortingCallbacks"] = {};
|
|
||||||
const searchFilters: CategoryColumns["searchFilters"] = [];
|
|
||||||
const renderTableHeader: CategoryColumns["renderTableHeader"] = [];
|
|
||||||
const tableRowRenderers: ((entity: CatalogEntity) => React.ReactNode)[] = [];
|
|
||||||
|
|
||||||
for (const registration of allRegistrations) {
|
|
||||||
if (registration.sortCallback) {
|
|
||||||
sortingCallbacks[registration.id] = registration.sortCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (registration.searchFilter) {
|
|
||||||
searchFilters.push(registration.searchFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
tableRowRenderers.push(registration.renderCell);
|
|
||||||
renderTableHeader.push(registration.titleProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
sortingCallbacks,
|
|
||||||
renderTableHeader,
|
|
||||||
renderTableContents: entity => tableRowRenderers.map(fn => fn(entity)),
|
|
||||||
searchFilters,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getCategoryColumnsInjectable = getInjectable({
|
|
||||||
id: "get-category-columns",
|
|
||||||
|
|
||||||
instantiate: (di) => getCategoryColumns({
|
|
||||||
extensionColumns: di.inject(categoryColumnsInjectable),
|
|
||||||
nameCategoryColumn: di.inject(nameCategoryColumnInjectable),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default getCategoryColumnsInjectable;
|
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import styles from "./catalog.module.scss";
|
||||||
|
import React from "react";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type { CatalogEntity } from "../../api/catalog-entity";
|
||||||
|
import searchUrlPageParamInjectable from "../input/search-url-page-param.injectable";
|
||||||
|
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||||
|
import { Badge } from "../badge";
|
||||||
|
|
||||||
|
export type GetLabelBadges = (entity: CatalogEntity, onClick?: ((evt: React.MouseEvent<any, MouseEvent>) => void) | undefined) => JSX.Element[];
|
||||||
|
|
||||||
|
const getLabelBadgesInjectable = getInjectable({
|
||||||
|
id: "get-label-badges",
|
||||||
|
instantiate: (di): GetLabelBadges => {
|
||||||
|
const searchUrlParam = di.inject(searchUrlPageParamInjectable);
|
||||||
|
|
||||||
|
return (entity, onClick) => (
|
||||||
|
KubeObject.stringifyLabels(entity.metadata.labels)
|
||||||
|
.map(label => (
|
||||||
|
<Badge
|
||||||
|
scrollable
|
||||||
|
className={styles.badge}
|
||||||
|
key={label}
|
||||||
|
label={label}
|
||||||
|
title={label}
|
||||||
|
onClick={(event) => {
|
||||||
|
searchUrlParam.set(label);
|
||||||
|
onClick?.(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
|
expandable={false}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getLabelBadgesInjectable;
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import styles from "./catalog.module.scss";
|
|
||||||
import React from "react";
|
|
||||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
|
||||||
import type { CatalogEntity } from "../../api/catalog-entity";
|
|
||||||
import { Badge } from "../badge";
|
|
||||||
import { searchUrlParam } from "../input";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param entity The entity to render badge labels for
|
|
||||||
*/
|
|
||||||
export function getLabelBadges(entity: CatalogEntity, onClick?: (evt: React.MouseEvent<any, MouseEvent>) => void) {
|
|
||||||
return KubeObject.stringifyLabels(entity.metadata.labels)
|
|
||||||
.map(label => (
|
|
||||||
<Badge
|
|
||||||
scrollable
|
|
||||||
className={styles.badge}
|
|
||||||
key={label}
|
|
||||||
label={label}
|
|
||||||
title={label}
|
|
||||||
onClick={(event) => {
|
|
||||||
searchUrlParam.set(label);
|
|
||||||
onClick?.(event);
|
|
||||||
event.stopPropagation();
|
|
||||||
}}
|
|
||||||
expandable={false}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import styles from "./catalog.module.scss";
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import type { RegisteredAdditionalCategoryColumn } from "./custom-category-columns";
|
|
||||||
import { getLabelBadges } from "./helpers";
|
|
||||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
|
||||||
|
|
||||||
export const browseAllColumns: RegisteredAdditionalCategoryColumn[] = [
|
|
||||||
{
|
|
||||||
id: "kind",
|
|
||||||
priority: 5,
|
|
||||||
renderCell: entity => entity.kind,
|
|
||||||
titleProps: {
|
|
||||||
id: "kind",
|
|
||||||
sortBy: "kind",
|
|
||||||
title: "Kind",
|
|
||||||
},
|
|
||||||
sortCallback: entity => entity.kind,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const defaultCategoryColumns: RegisteredAdditionalCategoryColumn[] = [
|
|
||||||
{
|
|
||||||
id: "source",
|
|
||||||
priority: 10,
|
|
||||||
renderCell: entity => entity.getSource(),
|
|
||||||
titleProps: {
|
|
||||||
title: "Source",
|
|
||||||
className: styles.sourceCell,
|
|
||||||
id: "source",
|
|
||||||
sortBy: "source",
|
|
||||||
},
|
|
||||||
sortCallback: entity => entity.getSource(),
|
|
||||||
searchFilter: entity => `source=${entity.getSource()}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "labels",
|
|
||||||
priority: 20,
|
|
||||||
renderCell: getLabelBadges,
|
|
||||||
titleProps: {
|
|
||||||
id: "labels",
|
|
||||||
title: "Labels",
|
|
||||||
className: `${styles.labelsCell} scrollable`,
|
|
||||||
},
|
|
||||||
searchFilter: entity => KubeObject.stringifyLabels(entity.metadata.labels),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "status",
|
|
||||||
priority: 30,
|
|
||||||
renderCell: entity => (
|
|
||||||
<span key="phase" className={entity.status.phase}>
|
|
||||||
{entity.status.phase}
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
titleProps: {
|
|
||||||
title: "Status",
|
|
||||||
className: styles.statusCell,
|
|
||||||
id: "status",
|
|
||||||
sortBy: "status",
|
|
||||||
},
|
|
||||||
searchFilter: entity => entity.status.phase,
|
|
||||||
sortCallback: entity => entity.status.phase,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@ -17,7 +17,7 @@ import { ClusterIssues } from "./cluster-issues";
|
|||||||
import { ClusterMetrics } from "./cluster-metrics";
|
import { ClusterMetrics } from "./cluster-metrics";
|
||||||
import type { ClusterOverviewStore } from "./cluster-overview-store/cluster-overview-store";
|
import type { ClusterOverviewStore } from "./cluster-overview-store/cluster-overview-store";
|
||||||
import { ClusterPieCharts } from "./cluster-pie-charts";
|
import { ClusterPieCharts } from "./cluster-pie-charts";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog/entity/legacy-globals";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import type { EventStore } from "../+events/store";
|
import type { EventStore } from "../+events/store";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import createPageParamInjectable from "../../navigation/create-page-param.injectable";
|
||||||
|
|
||||||
|
const crdGroupsUrlParamInjectable = getInjectable({
|
||||||
|
id: "crd-groups-url-param",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const createPageParam = di.inject(createPageParamInjectable);
|
||||||
|
|
||||||
|
return createPageParam<string[]>({
|
||||||
|
name: "groups",
|
||||||
|
defaultValue: [],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default crdGroupsUrlParamInjectable;
|
||||||
@ -13,15 +13,14 @@ import { iter, stopPropagation } from "../../utils";
|
|||||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||||
import { customResourceDefinitionStore } from "./legacy-store";
|
import { customResourceDefinitionStore } from "./legacy-store";
|
||||||
import { Select } from "../select";
|
import { Select } from "../select";
|
||||||
import { createPageParam } from "../../navigation";
|
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { KubeObjectAge } from "../kube-object/age";
|
import { KubeObjectAge } from "../kube-object/age";
|
||||||
import { TabLayout } from "../layout/tab-layout-2";
|
import { TabLayout } from "../layout/tab-layout-2";
|
||||||
|
import type { PageParam } from "../../navigation";
|
||||||
export const crdGroupsUrlParam = createPageParam<string[]>({
|
import type { CustomResourceDefinitionStore } from "./definition.store";
|
||||||
name: "groups",
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
defaultValue: [],
|
import crdGroupsUrlParamInjectable from "./crd-groups-url-param.injectable";
|
||||||
});
|
import customResourceDefinitionStoreInjectable from "./definition.store.injectable";
|
||||||
|
|
||||||
enum columnId {
|
enum columnId {
|
||||||
kind = "kind",
|
kind = "kind",
|
||||||
@ -31,25 +30,30 @@ enum columnId {
|
|||||||
age = "age",
|
age = "age",
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
interface Dependencies {
|
||||||
export class CustomResourceDefinitions extends React.Component {
|
crdGroupsUrlParam: PageParam<string[]>;
|
||||||
private readonly selectedGroups = observable.set(crdGroupsUrlParam.get());
|
customResourceDefinitionStore: CustomResourceDefinitionStore;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props: {}) {
|
@observer
|
||||||
|
class NonInjectedCustomResourceDefinitions extends React.Component<Dependencies> {
|
||||||
|
private readonly selectedGroups = observable.set(this.props.crdGroupsUrlParam.get());
|
||||||
|
|
||||||
|
constructor(props: Dependencies) {
|
||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get items() {
|
@computed get items() {
|
||||||
if (this.selectedGroups.size) {
|
if (this.selectedGroups.size) {
|
||||||
return customResourceDefinitionStore.items.filter(item => this.selectedGroups.has(item.getGroup()));
|
return this.props.customResourceDefinitionStore.items.filter(item => this.selectedGroups.has(item.getGroup()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return customResourceDefinitionStore.items; // show all by default
|
return this.props.customResourceDefinitionStore.items; // show all by default
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get groupSelectOptions() {
|
@computed get groupSelectOptions() {
|
||||||
return Object.keys(customResourceDefinitionStore.groups)
|
return Object.keys(this.props.customResourceDefinitionStore.groups)
|
||||||
.map(group => ({
|
.map(group => ({
|
||||||
value: group,
|
value: group,
|
||||||
label: group,
|
label: group,
|
||||||
@ -61,7 +65,7 @@ export class CustomResourceDefinitions extends React.Component {
|
|||||||
const groups = options.map(({ value }) => value);
|
const groups = options.map(({ value }) => value);
|
||||||
|
|
||||||
this.selectedGroups.replace(groups);
|
this.selectedGroups.replace(groups);
|
||||||
crdGroupsUrlParam.set(groups);
|
this.props.crdGroupsUrlParam.set(groups);
|
||||||
};
|
};
|
||||||
|
|
||||||
private getPlaceholder() {
|
private getPlaceholder() {
|
||||||
@ -159,3 +163,11 @@ export class CustomResourceDefinitions extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CustomResourceDefinitions = withInjectables<Dependencies>(NonInjectedCustomResourceDefinitions, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
crdGroupsUrlParam: di.inject(crdGroupsUrlParamInjectable),
|
||||||
|
customResourceDefinitionStore: di.inject(customResourceDefinitionStoreInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|||||||
@ -9,10 +9,9 @@ import React from "react";
|
|||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import { observable, makeObservable, computed } from "mobx";
|
import { observable, makeObservable, computed } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { navigation } from "../../navigation";
|
|
||||||
import { Tabs, Tab } from "../tabs";
|
import { Tabs, Tab } from "../tabs";
|
||||||
import type { CatalogEntity } from "../../api/catalog-entity";
|
import type { CatalogEntity } from "../../api/catalog-entity";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import { EntitySettingRegistry } from "../../../extensions/registries";
|
import { EntitySettingRegistry } from "../../../extensions/registries";
|
||||||
import { groupBy } from "lodash";
|
import { groupBy } from "lodash";
|
||||||
import { SettingLayout } from "../layout/setting-layout";
|
import { SettingLayout } from "../layout/setting-layout";
|
||||||
@ -20,9 +19,14 @@ import logger from "../../../common/logger";
|
|||||||
import { Avatar } from "../avatar";
|
import { Avatar } from "../avatar";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import entitySettingsRouteParametersInjectable from "./entity-settings-route-parameters.injectable";
|
import entitySettingsRouteParametersInjectable from "./entity-settings-route-parameters.injectable";
|
||||||
|
import type { ObservableHistory } from "mobx-observable-history";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
import observableHistoryInjectable from "../../navigation/observable-history.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
entityId: IComputedValue<string>;
|
entityId: IComputedValue<string>;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
|
observableHistory: ObservableHistory<unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -33,7 +37,7 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
|
|
||||||
const { hash } = navigation.location;
|
const { hash } = this.props.observableHistory.location;
|
||||||
|
|
||||||
if (hash) {
|
if (hash) {
|
||||||
const menuId = hash.slice(1);
|
const menuId = hash.slice(1);
|
||||||
@ -50,8 +54,8 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
return this.props.entityId.get();
|
return this.props.entityId.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
get entity(): CatalogEntity {
|
get entity() {
|
||||||
return catalogEntityRegistry.getById(this.entityId);
|
return this.props.entityRegistry.getById(this.entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
get menuItems() {
|
get menuItems() {
|
||||||
@ -70,7 +74,7 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
this.activeTab = tabId;
|
this.activeTab = tabId;
|
||||||
};
|
};
|
||||||
|
|
||||||
renderNavigation() {
|
renderNavigation(entity: CatalogEntity) {
|
||||||
const groups = Object.entries(groupBy(this.menuItems, (item) => item.group || "Extensions"));
|
const groups = Object.entries(groupBy(this.menuItems, (item) => item.group || "Extensions"));
|
||||||
|
|
||||||
groups.sort((a, b) => {
|
groups.sort((a, b) => {
|
||||||
@ -84,14 +88,14 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
<>
|
<>
|
||||||
<div className="flex items-center pb-8">
|
<div className="flex items-center pb-8">
|
||||||
<Avatar
|
<Avatar
|
||||||
title={this.entity.getName()}
|
title={entity.getName()}
|
||||||
colorHash={`${this.entity.getName()}-${this.entity.metadata.source}`}
|
colorHash={`${entity.getName()}-${entity.metadata.source}`}
|
||||||
src={this.entity.spec.icon?.src}
|
src={entity.spec.icon?.src}
|
||||||
className={styles.settingsAvatar}
|
className={styles.settingsAvatar}
|
||||||
size={40}
|
size={40}
|
||||||
/>
|
/>
|
||||||
<div className={styles.entityName}>
|
<div className={styles.entityName}>
|
||||||
{this.entity.getName()}
|
{entity.getName()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Tabs
|
<Tabs
|
||||||
@ -120,17 +124,17 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.entity) {
|
const { activeSetting, entity } = this;
|
||||||
|
|
||||||
|
if (!entity) {
|
||||||
logger.error("[ENTITY-SETTINGS]: entity not found", this.entityId);
|
logger.error("[ENTITY-SETTINGS]: entity not found", this.entityId);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { activeSetting } = this;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingLayout
|
<SettingLayout
|
||||||
navigation={this.renderNavigation()}
|
navigation={this.renderNavigation(entity)}
|
||||||
contentGaps={false}
|
contentGaps={false}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
@ -138,7 +142,7 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
<section>
|
<section>
|
||||||
<h2 data-testid={`${activeSetting.id}-header`}>{activeSetting.title}</h2>
|
<h2 data-testid={`${activeSetting.id}-header`}>{activeSetting.title}</h2>
|
||||||
<section>
|
<section>
|
||||||
<activeSetting.components.View entity={this.entity} key={activeSetting.title} />
|
<activeSetting.components.View entity={entity} key={activeSetting.title} />
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
@ -148,16 +152,10 @@ class NonInjectedEntitySettings extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EntitySettings = withInjectables<Dependencies>(
|
export const EntitySettings = withInjectables<Dependencies>(NonInjectedEntitySettings, {
|
||||||
NonInjectedEntitySettings,
|
getProps: (di) => ({
|
||||||
|
...di.inject(entitySettingsRouteParametersInjectable),
|
||||||
{
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
getProps: (di) => {
|
observableHistory: di.inject(observableHistoryInjectable),
|
||||||
const routeParameters = di.inject(entitySettingsRouteParametersInjectable);
|
}),
|
||||||
|
});
|
||||||
return {
|
|
||||||
entityId: routeParameters.entityId,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -14,25 +14,33 @@ import { getMetricsForNamespace, type PodMetricData, Namespace } from "../../../
|
|||||||
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Spinner } from "../spinner";
|
import { Spinner } from "../spinner";
|
||||||
import { resourceQuotaStore } from "../+config-resource-quotas/legacy-store";
|
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { limitRangeStore } from "../+config-limit-ranges/legacy-store";
|
|
||||||
import { ResourceMetrics } from "../resource-metrics";
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { getDetailsUrl } from "../kube-detail-params";
|
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
|
||||||
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
||||||
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable";
|
||||||
|
import type { ResourceQuotaStore } from "../+config-resource-quotas/store";
|
||||||
|
import type { LimitRangeStore } from "../+config-limit-ranges/store";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable";
|
||||||
|
import limitRangeStoreInjectable from "../+config-limit-ranges/store.injectable";
|
||||||
|
import resourceQuotaStoreInjectable from "../+config-resource-quotas/store.injectable";
|
||||||
|
|
||||||
export interface NamespaceDetailsProps extends KubeObjectDetailsProps<Namespace> {
|
export interface NamespaceDetailsProps extends KubeObjectDetailsProps<Namespace> {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
subscribeStores: SubscribeStores;
|
subscribeStores: SubscribeStores;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
|
getDetailsUrl: GetDetailsUrl;
|
||||||
|
resourceQuotaStore: ResourceQuotaStore;
|
||||||
|
limitRangeStore: LimitRangeStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -51,8 +59,8 @@ class NonInjectedNamespaceDetails extends React.Component<NamespaceDetailsProps
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
this.props.subscribeStores([
|
this.props.subscribeStores([
|
||||||
resourceQuotaStore,
|
this.props.resourceQuotaStore,
|
||||||
limitRangeStore,
|
this.props.limitRangeStore,
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -60,13 +68,13 @@ class NonInjectedNamespaceDetails extends React.Component<NamespaceDetailsProps
|
|||||||
@computed get quotas() {
|
@computed get quotas() {
|
||||||
const namespace = this.props.object.getName();
|
const namespace = this.props.object.getName();
|
||||||
|
|
||||||
return resourceQuotaStore.getAllByNs(namespace);
|
return this.props.resourceQuotaStore.getAllByNs(namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get limitranges() {
|
@computed get limitranges() {
|
||||||
const namespace = this.props.object.getName();
|
const namespace = this.props.object.getName();
|
||||||
|
|
||||||
return limitRangeStore.getAllByNs(namespace);
|
return this.props.limitRangeStore.getAllByNs(namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMetrics = async () => {
|
loadMetrics = async () => {
|
||||||
@ -74,7 +82,7 @@ class NonInjectedNamespaceDetails extends React.Component<NamespaceDetailsProps
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: namespace } = this.props;
|
const { object: namespace, getActiveClusterEntity, resourceQuotaStore, getDetailsUrl, limitRangeStore } = this.props;
|
||||||
|
|
||||||
if (!namespace) {
|
if (!namespace) {
|
||||||
return null;
|
return null;
|
||||||
@ -109,23 +117,19 @@ class NonInjectedNamespaceDetails extends React.Component<NamespaceDetailsProps
|
|||||||
|
|
||||||
<DrawerItem name="Resource Quotas" className="quotas flex align-center">
|
<DrawerItem name="Resource Quotas" className="quotas flex align-center">
|
||||||
{!this.quotas && resourceQuotaStore.isLoading && <Spinner/>}
|
{!this.quotas && resourceQuotaStore.isLoading && <Spinner/>}
|
||||||
{this.quotas.map(quota => {
|
{this.quotas.map(quota => quota.selfLink && (
|
||||||
return quota.selfLink && (
|
<Link key={quota.getId()} to={getDetailsUrl(quota.selfLink)}>
|
||||||
<Link key={quota.getId()} to={getDetailsUrl(quota.selfLink)}>
|
{quota.getName()}
|
||||||
{quota.getName()}
|
</Link>
|
||||||
</Link>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</DrawerItem>
|
</DrawerItem>
|
||||||
<DrawerItem name="Limit Ranges">
|
<DrawerItem name="Limit Ranges">
|
||||||
{!this.limitranges && limitRangeStore.isLoading && <Spinner/>}
|
{!this.limitranges && limitRangeStore.isLoading && <Spinner/>}
|
||||||
{this.limitranges.map(limitrange => {
|
{this.limitranges.map(limitrange => limitrange.selfLink && (
|
||||||
return limitrange.selfLink && (
|
<Link key={limitrange.getId()} to={getDetailsUrl(limitrange.selfLink)}>
|
||||||
<Link key={limitrange.getId()} to={getDetailsUrl(limitrange.selfLink)}>
|
{limitrange.getName()}
|
||||||
{limitrange.getName()}
|
</Link>
|
||||||
</Link>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</DrawerItem>
|
</DrawerItem>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -136,6 +140,10 @@ export const NamespaceDetails = withInjectables<Dependencies, NamespaceDetailsPr
|
|||||||
getProps: (di, props) => ({
|
getProps: (di, props) => ({
|
||||||
...props,
|
...props,
|
||||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
|
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||||
|
limitRangeStore: di.inject(limitRangeStoreInjectable),
|
||||||
|
resourceQuotaStore: di.inject(resourceQuotaStoreInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import type { KubeObjectDetailsProps } from "../kube-object-details";
|
|||||||
import { IngressCharts } from "./ingress-charts";
|
import { IngressCharts } from "./ingress-charts";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { computeRuleDeclarations, getMetricsForIngress, type IngressMetricData } from "../../../common/k8s-api/endpoints/ingress.api";
|
import { computeRuleDeclarations, getMetricsForIngress, type IngressMetricData } from "../../../common/k8s-api/endpoints/ingress.api";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog/entity/legacy-globals";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import { NodeCharts } from "./node-charts";
|
|||||||
import { makeObservable, observable, reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import { NodeDetailsResources } from "./details-resources";
|
import { NodeDetailsResources } from "./details-resources";
|
||||||
import { DrawerTitle } from "../drawer/drawer-title";
|
import { DrawerTitle } from "../drawer/drawer-title";
|
||||||
@ -29,6 +28,8 @@ import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
|||||||
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
||||||
import type { PodStore } from "../+workloads-pods/store";
|
import type { PodStore } from "../+workloads-pods/store";
|
||||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface NodeDetailsProps extends KubeObjectDetailsProps<Node> {
|
export interface NodeDetailsProps extends KubeObjectDetailsProps<Node> {
|
||||||
}
|
}
|
||||||
@ -36,6 +37,7 @@ export interface NodeDetailsProps extends KubeObjectDetailsProps<Node> {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
subscribeStores: SubscribeStores;
|
subscribeStores: SubscribeStores;
|
||||||
podStore: PodStore;
|
podStore: PodStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -66,7 +68,7 @@ class NonInjectedNodeDetails extends React.Component<NodeDetailsProps & Dependen
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: node, podStore } = this.props;
|
const { object: node, podStore, getActiveClusterEntity } = this.props;
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return null;
|
return null;
|
||||||
@ -193,6 +195,7 @@ export const NodeDetails = withInjectables<Dependencies, NodeDetailsProps>(NonIn
|
|||||||
...props,
|
...props,
|
||||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
podStore: di.inject(podStoreInjectable),
|
podStore: di.inject(podStoreInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import { ResourceMetrics } from "../resource-metrics";
|
|||||||
import { VolumeClaimDiskChart } from "./volume-claim-disk-chart";
|
import { VolumeClaimDiskChart } from "./volume-claim-disk-chart";
|
||||||
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
||||||
import { getMetricsForPvc, type PersistentVolumeClaimMetricData, PersistentVolumeClaim } from "../../../common/k8s-api/endpoints";
|
import { getMetricsForPvc, type PersistentVolumeClaimMetricData, PersistentVolumeClaim } from "../../../common/k8s-api/endpoints";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog/entity/legacy-globals";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getDetailsUrl } from "../kube-detail-params";
|
import { getDetailsUrl } from "../kube-detail-params";
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
|||||||
import { makeObservable, observable, reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
@ -29,6 +28,8 @@ import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
|||||||
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
||||||
import daemonSetStoreInjectable from "./store.injectable";
|
import daemonSetStoreInjectable from "./store.injectable";
|
||||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface DaemonSetDetailsProps extends KubeObjectDetailsProps<DaemonSet> {
|
export interface DaemonSetDetailsProps extends KubeObjectDetailsProps<DaemonSet> {
|
||||||
}
|
}
|
||||||
@ -37,6 +38,7 @@ interface Dependencies {
|
|||||||
subscribeStores: SubscribeStores;
|
subscribeStores: SubscribeStores;
|
||||||
daemonSetStore: DaemonSetStore;
|
daemonSetStore: DaemonSetStore;
|
||||||
podStore: PodStore;
|
podStore: PodStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -66,7 +68,7 @@ class NonInjectedDaemonSetDetails extends React.Component<DaemonSetDetailsProps
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: daemonSet, daemonSetStore, podStore } = this.props;
|
const { object: daemonSet, daemonSetStore, podStore, getActiveClusterEntity } = this.props;
|
||||||
|
|
||||||
if (!daemonSet) {
|
if (!daemonSet) {
|
||||||
return null;
|
return null;
|
||||||
@ -140,5 +142,6 @@ export const DaemonSetDetails = withInjectables<Dependencies, DaemonSetDetailsPr
|
|||||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
daemonSetStore: di.inject(daemonSetStoreInjectable),
|
daemonSetStore: di.inject(daemonSetStoreInjectable),
|
||||||
podStore: di.inject(podStoreInjectable),
|
podStore: di.inject(podStoreInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -23,7 +23,6 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
|||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import type { ReplicaSetStore } from "../+workloads-replicasets/store";
|
import type { ReplicaSetStore } from "../+workloads-replicasets/store";
|
||||||
import { DeploymentReplicaSets } from "./deployment-replicasets";
|
import { DeploymentReplicaSets } from "./deployment-replicasets";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
@ -33,6 +32,8 @@ import type { PodStore } from "../+workloads-pods/store";
|
|||||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||||
import replicaSetStoreInjectable from "../+workloads-replicasets/store.injectable";
|
import replicaSetStoreInjectable from "../+workloads-replicasets/store.injectable";
|
||||||
import deploymentStoreInjectable from "./store.injectable";
|
import deploymentStoreInjectable from "./store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface DeploymentDetailsProps extends KubeObjectDetailsProps<Deployment> {
|
export interface DeploymentDetailsProps extends KubeObjectDetailsProps<Deployment> {
|
||||||
}
|
}
|
||||||
@ -42,6 +43,7 @@ interface Dependencies {
|
|||||||
podStore: PodStore;
|
podStore: PodStore;
|
||||||
replicaSetStore: ReplicaSetStore;
|
replicaSetStore: ReplicaSetStore;
|
||||||
deploymentStore: DeploymentStore;
|
deploymentStore: DeploymentStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -73,7 +75,7 @@ class NonInjectedDeploymentDetails extends React.Component<DeploymentDetailsProp
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: deployment, podStore, replicaSetStore, deploymentStore } = this.props;
|
const { object: deployment, podStore, replicaSetStore, deploymentStore, getActiveClusterEntity } = this.props;
|
||||||
|
|
||||||
if (!deployment) {
|
if (!deployment) {
|
||||||
return null;
|
return null;
|
||||||
@ -174,6 +176,7 @@ export const DeploymentDetails = withInjectables<Dependencies, DeploymentDetails
|
|||||||
podStore: di.inject(podStoreInjectable),
|
podStore: di.inject(podStoreInjectable),
|
||||||
replicaSetStore: di.inject(replicaSetStoreInjectable),
|
replicaSetStore: di.inject(replicaSetStoreInjectable),
|
||||||
deploymentStore: di.inject(deploymentStoreInjectable),
|
deploymentStore: di.inject(deploymentStoreInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -22,10 +22,8 @@ import { KubeObjectMeta } from "../kube-object-meta";
|
|||||||
import { makeObservable, observable, reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts";
|
import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ResourceMetrics } from "../resource-metrics";
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
import { getDetailsUrl } from "../kube-detail-params";
|
import type { ApiManager } from "../../../common/k8s-api/api-manager";
|
||||||
import { apiManager } from "../../../common/k8s-api/api-manager";
|
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
||||||
@ -33,6 +31,11 @@ import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.inj
|
|||||||
import type { PodStore } from "../+workloads-pods/store";
|
import type { PodStore } from "../+workloads-pods/store";
|
||||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||||
import jobStoreInjectable from "./store.injectable";
|
import jobStoreInjectable from "./store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable";
|
||||||
|
import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable";
|
||||||
|
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface JobDetailsProps extends KubeObjectDetailsProps<Job> {
|
export interface JobDetailsProps extends KubeObjectDetailsProps<Job> {
|
||||||
}
|
}
|
||||||
@ -41,6 +44,9 @@ interface Dependencies {
|
|||||||
subscribeStores: SubscribeStores;
|
subscribeStores: SubscribeStores;
|
||||||
podStore: PodStore;
|
podStore: PodStore;
|
||||||
jobStore: JobStore;
|
jobStore: JobStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
|
getDetailsUrl: GetDetailsUrl;
|
||||||
|
apiManager: ApiManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -70,7 +76,7 @@ class NonInjectedJobDetails extends React.Component<JobDetailsProps & Dependenci
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: job, jobStore } = this.props;
|
const { object: job, jobStore, getActiveClusterEntity, getDetailsUrl, apiManager } = this.props;
|
||||||
|
|
||||||
if (!job) {
|
if (!job) {
|
||||||
return null;
|
return null;
|
||||||
@ -178,6 +184,9 @@ export const JobDetails = withInjectables<Dependencies, JobDetailsProps>(NonInje
|
|||||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
podStore: di.inject(podStoreInjectable),
|
podStore: di.inject(podStoreInjectable),
|
||||||
jobStore: di.inject(jobStoreInjectable),
|
jobStore: di.inject(jobStoreInjectable),
|
||||||
|
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||||
|
apiManager: di.inject(apiManagerInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -17,12 +17,13 @@ import { ResourceMetrics } from "../resource-metrics";
|
|||||||
import type { MetricData } from "../../../common/k8s-api/endpoints/metrics.api";
|
import type { MetricData } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||||
import { ContainerCharts } from "./container-charts";
|
import { ContainerCharts } from "./container-charts";
|
||||||
import { LocaleDate } from "../locale-date";
|
import { LocaleDate } from "../locale-date";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import type { PortForwardStore } from "../../port-forward";
|
import type { PortForwardStore } from "../../port-forward";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable";
|
import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface PodDetailsContainerProps {
|
export interface PodDetailsContainerProps {
|
||||||
pod: Pod;
|
pod: Pod;
|
||||||
@ -32,6 +33,7 @@ export interface PodDetailsContainerProps {
|
|||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
portForwardStore: PortForwardStore;
|
portForwardStore: PortForwardStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -82,7 +84,7 @@ class NonInjectedPodDetailsContainer extends React.Component<PodDetailsContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { pod, container, metrics } = this.props;
|
const { pod, container, metrics, getActiveClusterEntity } = this.props;
|
||||||
|
|
||||||
if (!pod || !container) return null;
|
if (!pod || !container) return null;
|
||||||
const { name, image, imagePullPolicy, ports, volumeMounts, command, args } = container;
|
const { name, image, imagePullPolicy, ports, volumeMounts, command, args } = container;
|
||||||
@ -211,13 +213,10 @@ class NonInjectedPodDetailsContainer extends React.Component<PodDetailsContainer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PodDetailsContainer = withInjectables<Dependencies, PodDetailsContainerProps>(
|
export const PodDetailsContainer = withInjectables<Dependencies, PodDetailsContainerProps>(NonInjectedPodDetailsContainer, {
|
||||||
NonInjectedPodDetailsContainer,
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
{
|
portForwardStore: di.inject(portForwardStoreInjectable),
|
||||||
getProps: (di, props) => ({
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
portForwardStore: di.inject(portForwardStoreInjectable),
|
}),
|
||||||
...props,
|
});
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import type { KubeObjectDetailsProps } from "../kube-object-details";
|
|||||||
import { getItemMetrics } from "../../../common/k8s-api/endpoints/metrics.api";
|
import { getItemMetrics } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||||
import { PodCharts, podMetricTabs } from "./pod-charts";
|
import { PodCharts, podMetricTabs } from "./pod-charts";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog/entity/legacy-globals";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import { getDetailsUrl } from "../kube-detail-params";
|
import { getDetailsUrl } from "../kube-detail-params";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
|||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
@ -29,6 +28,8 @@ import type { PodStore } from "../+workloads-pods/store";
|
|||||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||||
import type { ReplicaSetStore } from "./store";
|
import type { ReplicaSetStore } from "./store";
|
||||||
import replicaSetStoreInjectable from "./store.injectable";
|
import replicaSetStoreInjectable from "./store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface ReplicaSetDetailsProps extends KubeObjectDetailsProps<ReplicaSet> {
|
export interface ReplicaSetDetailsProps extends KubeObjectDetailsProps<ReplicaSet> {
|
||||||
}
|
}
|
||||||
@ -37,6 +38,7 @@ interface Dependencies {
|
|||||||
subscribeStores: SubscribeStores;
|
subscribeStores: SubscribeStores;
|
||||||
podStore: PodStore;
|
podStore: PodStore;
|
||||||
replicaSetStore: ReplicaSetStore;
|
replicaSetStore: ReplicaSetStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -67,7 +69,7 @@ class NonInjectedReplicaSetDetails extends React.Component<ReplicaSetDetailsProp
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: replicaSet, podStore, replicaSetStore } = this.props;
|
const { object: replicaSet, podStore, replicaSetStore, getActiveClusterEntity } = this.props;
|
||||||
|
|
||||||
if (!replicaSet) {
|
if (!replicaSet) {
|
||||||
return null;
|
return null;
|
||||||
@ -141,5 +143,6 @@ export const ReplicaSetDetails = withInjectables<Dependencies, ReplicaSetDetails
|
|||||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
podStore: di.inject(podStoreInjectable),
|
podStore: di.inject(podStoreInjectable),
|
||||||
replicaSetStore: di.inject(replicaSetStoreInjectable),
|
replicaSetStore: di.inject(replicaSetStoreInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
|||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
@ -30,6 +29,8 @@ import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.inj
|
|||||||
import type { PodStore } from "../+workloads-pods/store";
|
import type { PodStore } from "../+workloads-pods/store";
|
||||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||||
import statefulSetStoreInjectable from "./store.injectable";
|
import statefulSetStoreInjectable from "./store.injectable";
|
||||||
|
import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
export interface StatefulSetDetailsProps extends KubeObjectDetailsProps<StatefulSet> {
|
export interface StatefulSetDetailsProps extends KubeObjectDetailsProps<StatefulSet> {
|
||||||
}
|
}
|
||||||
@ -38,6 +39,7 @@ interface Dependencies {
|
|||||||
subscribeStores: SubscribeStores;
|
subscribeStores: SubscribeStores;
|
||||||
podStore: PodStore;
|
podStore: PodStore;
|
||||||
statefulSetStore: StatefulSetStore;
|
statefulSetStore: StatefulSetStore;
|
||||||
|
getActiveClusterEntity: GetActiveClusterEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -68,7 +70,7 @@ class NonInjectedStatefulSetDetails extends React.Component<StatefulSetDetailsPr
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: statefulSet, podStore, statefulSetStore } = this.props;
|
const { object: statefulSet, podStore, statefulSetStore, getActiveClusterEntity } = this.props;
|
||||||
|
|
||||||
if (!statefulSet) {
|
if (!statefulSet) {
|
||||||
return null;
|
return null;
|
||||||
@ -140,6 +142,7 @@ export const StatefulSetDetails = withInjectables<Dependencies, StatefulSetDetai
|
|||||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
podStore: di.inject(podStoreInjectable),
|
podStore: di.inject(podStoreInjectable),
|
||||||
statefulSetStore: di.inject(statefulSetStoreInjectable),
|
statefulSetStore: di.inject(statefulSetStoreInjectable),
|
||||||
|
getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,13 +5,12 @@
|
|||||||
|
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import { computed } from "mobx";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { broadcastMessage } from "../../../common/ipc";
|
import { broadcastMessage } from "../../../common/ipc";
|
||||||
import { catalogEntityRunListener } from "../../../common/ipc/catalog";
|
import { catalogEntityRunListener } from "../../../common/ipc/catalog";
|
||||||
import type { CatalogEntity } from "../../api/catalog-entity";
|
import type { CatalogEntity } from "../../api/catalog-entity";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import catalogEnitiesInjectable from "../../api/catalog/entity/entities.injectable";
|
||||||
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
||||||
import { Select } from "../select";
|
import { Select } from "../select";
|
||||||
|
|
||||||
@ -20,7 +19,10 @@ interface Dependencies {
|
|||||||
entities: IComputedValue<CatalogEntity[]>;
|
entities: IComputedValue<CatalogEntity[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NonInjectedActivateEntityCommand = observer(({ closeCommandOverlay, entities }: Dependencies) => (
|
const NonInjectedActivateEntityCommand = observer(({
|
||||||
|
closeCommandOverlay,
|
||||||
|
entities,
|
||||||
|
}: Dependencies) => (
|
||||||
<Select
|
<Select
|
||||||
id="activate-entity-input"
|
id="activate-entity-input"
|
||||||
menuPortalTarget={null}
|
menuPortalTarget={null}
|
||||||
@ -48,6 +50,6 @@ const NonInjectedActivateEntityCommand = observer(({ closeCommandOverlay, entiti
|
|||||||
export const ActivateEntityCommand = withInjectables<Dependencies>(NonInjectedActivateEntityCommand, {
|
export const ActivateEntityCommand = withInjectables<Dependencies>(NonInjectedActivateEntityCommand, {
|
||||||
getProps: di => ({
|
getProps: di => ({
|
||||||
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
||||||
entities: computed(() => [...catalogEntityRegistry.items]),
|
entities: di.inject(catalogEnitiesInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,11 +16,12 @@ import { Button } from "../button";
|
|||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { Spinner } from "../spinner";
|
import { Spinner } from "../spinner";
|
||||||
import type { KubeAuthUpdate } from "../../../common/cluster-types";
|
import type { KubeAuthUpdate } from "../../../common/cluster-types";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import { requestClusterActivation } from "../../ipc";
|
import { requestClusterActivation } from "../../ipc";
|
||||||
import type { NavigateToEntitySettings } from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
import type { NavigateToEntitySettings } from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
|
||||||
export interface ClusterStatusProps {
|
export interface ClusterStatusProps {
|
||||||
className?: IClassName;
|
className?: IClassName;
|
||||||
@ -29,6 +30,7 @@ export interface ClusterStatusProps {
|
|||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
navigateToEntitySettings: NavigateToEntitySettings;
|
navigateToEntitySettings: NavigateToEntitySettings;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -46,7 +48,7 @@ class NonInjectedClusterStatus extends React.Component<ClusterStatusProps & Depe
|
|||||||
}
|
}
|
||||||
|
|
||||||
@computed get entity() {
|
@computed get entity() {
|
||||||
return catalogEntityRegistry.getById(this.cluster.id);
|
return this.props.entityRegistry.getById(this.cluster.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get hasErrors(): boolean {
|
@computed get hasErrors(): boolean {
|
||||||
@ -158,13 +160,10 @@ class NonInjectedClusterStatus extends React.Component<ClusterStatusProps & Depe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ClusterStatus = withInjectables<Dependencies, ClusterStatusProps>(
|
export const ClusterStatus = withInjectables<Dependencies, ClusterStatusProps>(NonInjectedClusterStatus, {
|
||||||
NonInjectedClusterStatus,
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
{
|
navigateToEntitySettings: di.inject(navigateToEntitySettingsInjectable),
|
||||||
getProps: (di, props) => ({
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
navigateToEntitySettings: di.inject(navigateToEntitySettingsInjectable),
|
}),
|
||||||
...props,
|
});
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -12,18 +12,20 @@ import { ClusterStatus } from "./cluster-status";
|
|||||||
import type { ClusterFrameHandler } from "./lens-views";
|
import type { ClusterFrameHandler } from "./lens-views";
|
||||||
import type { Cluster } from "../../../common/cluster/cluster";
|
import type { Cluster } from "../../../common/cluster/cluster";
|
||||||
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
|
||||||
import { requestClusterActivation } from "../../ipc";
|
import { requestClusterActivation } from "../../ipc";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||||
import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||||
import clusterViewRouteParametersInjectable from "./cluster-view-route-parameters.injectable";
|
import clusterViewRouteParametersInjectable from "./cluster-view-route-parameters.injectable";
|
||||||
import clusterFramesInjectable from "./lens-views.injectable";
|
import clusterFramesInjectable from "./lens-views.injectable";
|
||||||
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
clusterId: IComputedValue<string>;
|
clusterId: IComputedValue<string>;
|
||||||
clusterFrames: ClusterFrameHandler;
|
clusterFrames: ClusterFrameHandler;
|
||||||
navigateToCatalog: NavigateToCatalog;
|
navigateToCatalog: NavigateToCatalog;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -60,7 +62,7 @@ class NonInjectedClusterView extends React.Component<Dependencies> {
|
|||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.clusterFrames.clearVisibleCluster();
|
this.props.clusterFrames.clearVisibleCluster();
|
||||||
catalogEntityRegistry.activeEntity = undefined;
|
this.props.entityRegistry.activeEntity = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
@ -69,7 +71,7 @@ class NonInjectedClusterView extends React.Component<Dependencies> {
|
|||||||
this.props.clusterFrames.setVisibleCluster(clusterId);
|
this.props.clusterFrames.setVisibleCluster(clusterId);
|
||||||
this.props.clusterFrames.initView(clusterId);
|
this.props.clusterFrames.initView(clusterId);
|
||||||
requestClusterActivation(clusterId, false); // activate and fetch cluster's state from main
|
requestClusterActivation(clusterId, false); // activate and fetch cluster's state from main
|
||||||
catalogEntityRegistry.activeEntity = clusterId;
|
this.props.entityRegistry.activeEntity = clusterId;
|
||||||
}, {
|
}, {
|
||||||
fireImmediately: true,
|
fireImmediately: true,
|
||||||
}),
|
}),
|
||||||
@ -106,6 +108,7 @@ export const ClusterView = withInjectables<Dependencies>(NonInjectedClusterView,
|
|||||||
clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId,
|
clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId,
|
||||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||||
clusterFrames: di.inject(clusterFramesInjectable),
|
clusterFrames: di.inject(clusterFramesInjectable),
|
||||||
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -13,20 +13,22 @@ import type { ClusterId } from "../../../common/cluster-types";
|
|||||||
import type { CommandOverlay } from "./command-overlay.injectable";
|
import type { CommandOverlay } from "./command-overlay.injectable";
|
||||||
import commandOverlayInjectable from "./command-overlay.injectable";
|
import commandOverlayInjectable from "./command-overlay.injectable";
|
||||||
import { isMac } from "../../../common/vars";
|
import { isMac } from "../../../common/vars";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import { broadcastMessage, ipcRendererOn } from "../../../common/ipc";
|
import { broadcastMessage, ipcRendererOn } from "../../../common/ipc";
|
||||||
import type { Disposer } from "../../utils";
|
import type { Disposer } from "../../utils";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import windowAddEventListenerInjectable from "../../window/event-listener.injectable";
|
import windowAddEventListenerInjectable from "../../window/event-listener.injectable";
|
||||||
import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable";
|
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import matchedClusterIdInjectable from "../../navigation/matched-cluster-id.injectable";
|
import matchedClusterIdInjectable from "../../navigation/matched-cluster-id.injectable";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
import hostedClusterIdInjectable from "../../../common/cluster-store/hosted-cluster-id.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
addWindowEventListener: <K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions) => Disposer;
|
addWindowEventListener: <K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions) => Disposer;
|
||||||
commandOverlay: CommandOverlay;
|
commandOverlay: CommandOverlay;
|
||||||
clusterId?: ClusterId;
|
clusterId?: ClusterId;
|
||||||
matchedClusterId: IComputedValue<ClusterId>;
|
matchedClusterId: IComputedValue<ClusterId>;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -41,12 +43,12 @@ class NonInjectedCommandContainer extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleCommandPalette = () => {
|
handleCommandPalette = () => {
|
||||||
const { commandOverlay } = this.props;
|
const { commandOverlay, entityRegistry } = this.props;
|
||||||
const clusterIsActive = this.props.matchedClusterId.get() !== undefined;
|
const clusterIsActive = this.props.matchedClusterId.get() !== undefined;
|
||||||
|
|
||||||
if (clusterIsActive) {
|
if (clusterIsActive) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
broadcastMessage(`command-palette:${catalogEntityRegistry.activeEntity!.getId()}:open`);
|
broadcastMessage(`command-palette:${entityRegistry.activeEntity!.getId()}:open`);
|
||||||
} else {
|
} else {
|
||||||
commandOverlay.open(<CommandDialog />);
|
commandOverlay.open(<CommandDialog />);
|
||||||
}
|
}
|
||||||
@ -97,19 +99,13 @@ class NonInjectedCommandContainer extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CommandContainer = withInjectables<Dependencies>(
|
export const CommandContainer = withInjectables<Dependencies>(NonInjectedCommandContainer, {
|
||||||
NonInjectedCommandContainer,
|
getProps: (di, props) => ({
|
||||||
{
|
...props,
|
||||||
getProps: (di, props) => {
|
clusterId: di.inject(hostedClusterIdInjectable),
|
||||||
const hostedCluster = di.inject(hostedClusterInjectable);
|
addWindowEventListener: di.inject(windowAddEventListenerInjectable),
|
||||||
|
commandOverlay: di.inject(commandOverlayInjectable),
|
||||||
return {
|
matchedClusterId: di.inject(matchedClusterIdInjectable),
|
||||||
clusterId: hostedCluster?.id,
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
addWindowEventListener: di.inject(windowAddEventListenerInjectable),
|
}),
|
||||||
commandOverlay: di.inject(commandOverlayInjectable),
|
});
|
||||||
matchedClusterId: di.inject(matchedClusterIdInjectable),
|
|
||||||
...props,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -10,24 +10,38 @@ import { observer } from "mobx-react";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import commandOverlayInjectable from "./command-overlay.injectable";
|
import commandOverlayInjectable from "./command-overlay.injectable";
|
||||||
import type { CatalogEntity } from "../../../common/catalog";
|
import type { CatalogEntity } from "../../../common/catalog";
|
||||||
import { navigate } from "../../navigation";
|
|
||||||
import { broadcastMessage } from "../../../common/ipc";
|
import { broadcastMessage } from "../../../common/ipc";
|
||||||
import { IpcRendererNavigationEvents } from "../../navigation/events";
|
import { IpcRendererNavigationEvents } from "../../navigation/events";
|
||||||
import type { RegisteredCommand } from "./registered-commands/commands";
|
import type { RegisteredCommand } from "./registered-commands/commands";
|
||||||
import { iter } from "../../utils";
|
import { iter } from "../../utils";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import registeredCommandsInjectable from "./registered-commands/registered-commands.injectable";
|
import registeredCommandsInjectable from "./registered-commands/registered-commands.injectable";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
|
||||||
import type { SingleValue } from "react-select";
|
import type { SingleValue } from "react-select";
|
||||||
|
import type { Navigate } from "../../navigation/navigate.injectable";
|
||||||
|
import navigateInjectable from "../../navigation/navigate.injectable";
|
||||||
|
import activeEntityInjectable from "../../api/catalog/entity/active.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
commands: IComputedValue<Map<string, RegisteredCommand>>;
|
commands: IComputedValue<Map<string, RegisteredCommand>>;
|
||||||
activeEntity: CatalogEntity;
|
activeEntity: IComputedValue<CatalogEntity | undefined>;
|
||||||
closeCommandOverlay: () => void;
|
closeCommandOverlay: () => void;
|
||||||
|
navigate: Navigate;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NonInjectedCommandDialog = observer(({ commands, activeEntity, closeCommandOverlay }: Dependencies) => {
|
const NonInjectedCommandDialog = observer(({
|
||||||
|
commands,
|
||||||
|
activeEntity,
|
||||||
|
closeCommandOverlay,
|
||||||
|
navigate,
|
||||||
|
}: Dependencies) => {
|
||||||
const [searchValue, setSearchValue] = useState("");
|
const [searchValue, setSearchValue] = useState("");
|
||||||
|
const entity = activeEntity.get();
|
||||||
|
|
||||||
|
if (!entity) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = { entity };
|
||||||
|
|
||||||
const executeAction = (option: SingleValue<typeof activeCommands[number]>) => {
|
const executeAction = (option: SingleValue<typeof activeCommands[number]>) => {
|
||||||
if (!option) {
|
if (!option) {
|
||||||
@ -37,7 +51,7 @@ const NonInjectedCommandDialog = observer(({ commands, activeEntity, closeComman
|
|||||||
try {
|
try {
|
||||||
closeCommandOverlay();
|
closeCommandOverlay();
|
||||||
option.value.action({
|
option.value.action({
|
||||||
entity: activeEntity,
|
...context,
|
||||||
navigate: (url, opts = {}) => {
|
navigate: (url, opts = {}) => {
|
||||||
const { forceRootFrame = false } = opts;
|
const { forceRootFrame = false } = opts;
|
||||||
|
|
||||||
@ -53,10 +67,6 @@ const NonInjectedCommandDialog = observer(({ commands, activeEntity, closeComman
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const context = {
|
|
||||||
entity: activeEntity,
|
|
||||||
};
|
|
||||||
|
|
||||||
const activeCommands = iter.pipeline(commands.get().values())
|
const activeCommands = iter.pipeline(commands.get().values())
|
||||||
.filter(command => {
|
.filter(command => {
|
||||||
try {
|
try {
|
||||||
@ -101,9 +111,8 @@ const NonInjectedCommandDialog = observer(({ commands, activeEntity, closeComman
|
|||||||
export const CommandDialog = withInjectables<Dependencies>(NonInjectedCommandDialog, {
|
export const CommandDialog = withInjectables<Dependencies>(NonInjectedCommandDialog, {
|
||||||
getProps: di => ({
|
getProps: di => ({
|
||||||
commands: di.inject(registeredCommandsInjectable),
|
commands: di.inject(registeredCommandsInjectable),
|
||||||
// TODO: replace with injection
|
activeEntity: di.inject(activeEntityInjectable),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
activeEntity: catalogEntityRegistry.activeEntity!,
|
|
||||||
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
||||||
|
navigate: di.inject(navigateInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,11 +6,11 @@
|
|||||||
import styles from "./hotbar-entity-icon.module.scss";
|
import styles from "./hotbar-entity-icon.module.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
|
||||||
import type { CatalogCategoryRegistry, CatalogEntity, CatalogEntityContextMenu } from "../../../common/catalog";
|
import type { CatalogCategoryRegistry, CatalogEntity, CatalogEntityContextMenu } from "../../../common/catalog";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
|
||||||
import type { IClassName } from "../../utils";
|
import type { IClassName } from "../../utils";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
@ -21,6 +21,7 @@ import { navigate } from "../../navigation";
|
|||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||||
import onContextMenuOpenInjectable from "../../../common/catalog/on-context-menu-open.injectable";
|
import onContextMenuOpenInjectable from "../../../common/catalog/on-context-menu-open.injectable";
|
||||||
|
import activeEntityInjectable from "../../api/catalog/entity/active.injectable";
|
||||||
|
|
||||||
export interface HotbarEntityIconProps {
|
export interface HotbarEntityIconProps {
|
||||||
entity: CatalogEntity;
|
entity: CatalogEntity;
|
||||||
@ -36,6 +37,7 @@ export interface HotbarEntityIconProps {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
onContextMenuOpen: OnContextMenuOpen;
|
onContextMenuOpen: OnContextMenuOpen;
|
||||||
catalogCategoryRegistry: CatalogCategoryRegistry;
|
catalogCategoryRegistry: CatalogCategoryRegistry;
|
||||||
|
activeEntity: IComputedValue<CatalogEntity | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -73,7 +75,7 @@ class NonInjectedHotbarEntityIcon extends React.Component<HotbarEntityIconProps
|
|||||||
}
|
}
|
||||||
|
|
||||||
isActive(item: CatalogEntity) {
|
isActive(item: CatalogEntity) {
|
||||||
return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId();
|
return this.props.activeEntity.get()?.metadata?.uid == item.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMenuOpen() {
|
onMenuOpen() {
|
||||||
@ -123,5 +125,6 @@ export const HotbarEntityIcon = withInjectables<Dependencies, HotbarEntityIconPr
|
|||||||
...props,
|
...props,
|
||||||
catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||||
onContextMenuOpen: di.inject(onContextMenuOpenInjectable),
|
onContextMenuOpen: di.inject(onContextMenuOpenInjectable),
|
||||||
|
activeEntity: di.inject(activeEntityInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { observer } from "mobx-react";
|
|||||||
import { HotbarEntityIcon } from "./hotbar-entity-icon";
|
import { HotbarEntityIcon } from "./hotbar-entity-icon";
|
||||||
import type { IClassName } from "../../utils";
|
import type { IClassName } from "../../utils";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import type { CatalogEntity } from "../../api/catalog-entity";
|
import type { CatalogEntity } from "../../api/catalog-entity";
|
||||||
import { DragDropContext, Draggable, Droppable, type DropResult } from "react-beautiful-dnd";
|
import { DragDropContext, Draggable, Droppable, type DropResult } from "react-beautiful-dnd";
|
||||||
import { HotbarSelector } from "./hotbar-selector";
|
import { HotbarSelector } from "./hotbar-selector";
|
||||||
@ -22,6 +22,7 @@ import { action, makeObservable, observable } from "mobx";
|
|||||||
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
|
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type { HotbarStore } from "../../../common/hotbars/store";
|
import type { HotbarStore } from "../../../common/hotbars/store";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
|
||||||
export interface HotbarMenuProps {
|
export interface HotbarMenuProps {
|
||||||
className?: IClassName;
|
className?: IClassName;
|
||||||
@ -29,6 +30,7 @@ export interface HotbarMenuProps {
|
|||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
hotbarStore: HotbarStore;
|
hotbarStore: HotbarStore;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -51,7 +53,7 @@ class NonInjectedHotbarMenu extends React.Component<Dependencies & HotbarMenuPro
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return catalogEntityRegistry.getById(item.entity.uid) ?? null;
|
return this.props.entityRegistry.getById(item.entity.uid) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -140,7 +142,7 @@ class NonInjectedHotbarMenu extends React.Component<Dependencies & HotbarMenuPro
|
|||||||
key={index}
|
key={index}
|
||||||
index={index}
|
index={index}
|
||||||
entity={entity}
|
entity={entity}
|
||||||
onClick={() => catalogEntityRegistry.onRun(entity)}
|
onClick={() => this.props.entityRegistry.onRun(entity)}
|
||||||
className={cssNames({ isDragging: snapshot.isDragging })}
|
className={cssNames({ isDragging: snapshot.isDragging })}
|
||||||
remove={this.removeItem}
|
remove={this.removeItem}
|
||||||
add={this.addItem}
|
add={this.addItem}
|
||||||
@ -192,13 +194,10 @@ class NonInjectedHotbarMenu extends React.Component<Dependencies & HotbarMenuPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HotbarMenu = withInjectables<Dependencies, HotbarMenuProps>(
|
export const HotbarMenu = withInjectables<Dependencies, HotbarMenuProps>(NonInjectedHotbarMenu, {
|
||||||
NonInjectedHotbarMenu,
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
{
|
hotbarStore: di.inject(hotbarStoreInjectable),
|
||||||
getProps: (di, props) => ({
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
hotbarStore: di.inject(hotbarStoreInjectable),
|
}),
|
||||||
...props,
|
});
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -9,26 +9,27 @@ import { autorun, observable, makeObservable } from "mobx";
|
|||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import type { InputProps } from "./input";
|
import type { InputProps } from "./input";
|
||||||
import { SearchInput } from "./search-input";
|
import { SearchInput } from "./search-input";
|
||||||
import { createPageParam } from "../../navigation";
|
import type { PageParam } from "../../navigation";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
export const searchUrlParam = createPageParam({
|
import searchUrlPageParamInjectable from "./search-url-page-param.injectable";
|
||||||
name: "search",
|
|
||||||
defaultValue: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
export interface SearchInputUrlProps extends InputProps {
|
export interface SearchInputUrlProps extends InputProps {
|
||||||
compact?: boolean; // show only search-icon when not focused
|
compact?: boolean; // show only search-icon when not focused
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
searchUrlParam: PageParam<string>;
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class SearchInputUrl extends React.Component<SearchInputUrlProps> {
|
class NonInjectedSearchInputUrl extends React.Component<SearchInputUrlProps & Dependencies> {
|
||||||
@observable inputVal = ""; // fix: use empty string on init to avoid react warnings
|
@observable inputVal = ""; // fix: use empty string on init to avoid react warnings
|
||||||
|
|
||||||
updateUrl = debounce((val: string) => searchUrlParam.set(val), 250);
|
readonly updateUrl = debounce((val: string) => this.props.searchUrlParam.set(val), 250);
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
autorun(() => this.inputVal = searchUrlParam.get()),
|
autorun(() => this.inputVal = this.props.searchUrlParam.get()),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ export class SearchInputUrl extends React.Component<SearchInputUrlProps> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: SearchInputUrlProps) {
|
constructor(props: SearchInputUrlProps & Dependencies) {
|
||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
@ -68,3 +69,10 @@ export class SearchInputUrl extends React.Component<SearchInputUrlProps> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const SearchInputUrl = withInjectables<Dependencies, SearchInputUrlProps>(NonInjectedSearchInputUrl, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
searchUrlParam: di.inject(searchUrlPageParamInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import createPageParamInjectable from "../../navigation/create-page-param.injectable";
|
||||||
|
|
||||||
|
const searchUrlPageParamInjectable = getInjectable({
|
||||||
|
id: "search-url-page-param",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const createPageParam = di.inject(createPageParamInjectable);
|
||||||
|
|
||||||
|
return createPageParam({
|
||||||
|
name: "search",
|
||||||
|
defaultValue: "",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default searchUrlPageParamInjectable;
|
||||||
@ -20,8 +20,7 @@ import { AddRemoveButtons } from "../add-remove-buttons";
|
|||||||
import { NoItems } from "../no-items";
|
import { NoItems } from "../no-items";
|
||||||
import { Spinner } from "../spinner";
|
import { Spinner } from "../spinner";
|
||||||
import type { ItemObject } from "../../../common/item.store";
|
import type { ItemObject } from "../../../common/item.store";
|
||||||
import type { Filter } from "./page-filters.store";
|
import type { Filter, PageFiltersStore } from "./page-filters/store";
|
||||||
import { pageFilters } from "./page-filters.store";
|
|
||||||
import type { ThemeStore } from "../../themes/store";
|
import type { ThemeStore } from "../../themes/store";
|
||||||
import { MenuActions } from "../menu/menu-actions";
|
import { MenuActions } from "../menu/menu-actions";
|
||||||
import { MenuItem } from "../menu";
|
import { MenuItem } from "../menu";
|
||||||
@ -30,6 +29,7 @@ import { UserStore } from "../../../common/user-store";
|
|||||||
import type { ItemListStore } from "./list-layout";
|
import type { ItemListStore } from "./list-layout";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import themeStoreInjectable from "../../themes/store.injectable";
|
import themeStoreInjectable from "../../themes/store.injectable";
|
||||||
|
import pageFiltersStoreInjectable from "./page-filters/store.injectable";
|
||||||
|
|
||||||
export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStores extends boolean> {
|
export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStores extends boolean> {
|
||||||
getFilters: () => Filter[];
|
getFilters: () => Filter[];
|
||||||
@ -68,10 +68,14 @@ export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStor
|
|||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
themeStore: ThemeStore;
|
themeStore: ThemeStore;
|
||||||
|
pageFiltersStore: PageFiltersStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class NonInjectedItemListLayoutContent<Item extends ItemObject, PreLoadStores extends boolean> extends React.Component<ItemListLayoutContentProps<Item, PreLoadStores> & Dependencies> {
|
class NonInjectedItemListLayoutContent<
|
||||||
|
Item extends ItemObject,
|
||||||
|
PreLoadStores extends boolean,
|
||||||
|
> extends React.Component<ItemListLayoutContentProps<Item, PreLoadStores> & Dependencies> {
|
||||||
constructor(props: ItemListLayoutContentProps<Item, PreLoadStores> & Dependencies) {
|
constructor(props: ItemListLayoutContentProps<Item, PreLoadStores> & Dependencies) {
|
||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
@ -221,7 +225,7 @@ class NonInjectedItemListLayoutContent<Item extends ItemObject, PreLoadStores ex
|
|||||||
<NoItems>
|
<NoItems>
|
||||||
No items found.
|
No items found.
|
||||||
<p>
|
<p>
|
||||||
<a onClick={() => pageFilters.reset()} className="contrast">
|
<a onClick={() => this.props.pageFiltersStore.reset()} className="contrast">
|
||||||
Reset filters?
|
Reset filters?
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@ -367,5 +371,6 @@ export const ItemListLayoutContent = withInjectables<Dependencies, ItemListLayou
|
|||||||
getProps: (di, props) => ({
|
getProps: (di, props) => ({
|
||||||
...props,
|
...props,
|
||||||
themeStore: di.inject(themeStoreInjectable),
|
themeStore: di.inject(themeStoreInjectable),
|
||||||
|
pageFiltersStore: di.inject(pageFiltersStoreInjectable),
|
||||||
}),
|
}),
|
||||||
}) as <Item extends ItemObject, PreLoadStores extends boolean>(props: ItemListLayoutContentProps<Item, PreLoadStores>) => React.ReactElement;
|
}) as <Item extends ItemObject, PreLoadStores extends boolean>(props: ItemListLayoutContentProps<Item, PreLoadStores>) => React.ReactElement;
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import type { IconProps } from "../icon";
|
import type { IconProps } from "../icon";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { FilterType } from "./page-filters.store";
|
import { FilterType } from "./page-filters/store";
|
||||||
|
|
||||||
export interface FilterIconProps extends Partial<IconProps> {
|
export interface FilterIconProps extends Partial<IconProps> {
|
||||||
type: FilterType;
|
type: FilterType;
|
||||||
|
|||||||
@ -6,9 +6,9 @@
|
|||||||
import "./item-list-layout.scss";
|
import "./item-list-layout.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { PageFiltersList } from "./page-filters-list";
|
import { PageFiltersList } from "./page-filters/list";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import type { Filter } from "./page-filters.store";
|
import type { Filter } from "./page-filters/store";
|
||||||
|
|
||||||
export interface ItemListLayoutFilterProps {
|
export interface ItemListLayoutFilterProps {
|
||||||
getIsReady: () => boolean;
|
getIsReady: () => boolean;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { observer } from "mobx-react";
|
|||||||
import type { IClassName } from "../../utils";
|
import type { IClassName } from "../../utils";
|
||||||
import { cssNames, isDefined } from "../../utils";
|
import { cssNames, isDefined } from "../../utils";
|
||||||
import type { ItemObject } from "../../../common/item.store";
|
import type { ItemObject } from "../../../common/item.store";
|
||||||
import type { Filter } from "./page-filters.store";
|
import type { Filter } from "./page-filters/store";
|
||||||
import type { HeaderCustomizer, HeaderPlaceholders, ItemListStore, SearchFilter } from "./list-layout";
|
import type { HeaderCustomizer, HeaderPlaceholders, ItemListStore, SearchFilter } from "./list-layout";
|
||||||
import { SearchInputUrl } from "../input";
|
import { SearchInputUrl } from "../input";
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,9 @@ import { autoBind, cssNames, noop } from "../../utils";
|
|||||||
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
||||||
import type { ItemObject } from "../../../common/item.store";
|
import type { ItemObject } from "../../../common/item.store";
|
||||||
import type { SearchInputUrlProps } from "../input";
|
import type { SearchInputUrlProps } from "../input";
|
||||||
import { FilterType, pageFilters } from "./page-filters.store";
|
import type { PageFiltersStore } from "./page-filters/store";
|
||||||
import { PageFiltersList } from "./page-filters-list";
|
import { FilterType } from "./page-filters/store";
|
||||||
|
import { PageFiltersList } from "./page-filters/list";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import itemListLayoutStorageInjectable from "./storage.injectable";
|
import itemListLayoutStorageInjectable from "./storage.injectable";
|
||||||
import { ItemListLayoutContent } from "./content";
|
import { ItemListLayoutContent } from "./content";
|
||||||
@ -28,6 +29,7 @@ import { observer } from "mobx-react";
|
|||||||
import type { Primitive } from "type-fest";
|
import type { Primitive } from "type-fest";
|
||||||
import type { SubscribableStore } from "../../kube-watch-api/kube-watch-api";
|
import type { SubscribableStore } from "../../kube-watch-api/kube-watch-api";
|
||||||
import selectedFilterNamespacesInjectable from "../../../common/k8s-api/selected-filter-namespaces.injectable";
|
import selectedFilterNamespacesInjectable from "../../../common/k8s-api/selected-filter-namespaces.injectable";
|
||||||
|
import pageFiltersStoreInjectable from "./page-filters/store.injectable";
|
||||||
|
|
||||||
export type SearchFilter<I extends ItemObject> = (item: I) => SingleOrMany<string | number | undefined | null>;
|
export type SearchFilter<I extends ItemObject> = (item: I) => SingleOrMany<string | number | undefined | null>;
|
||||||
export type SearchFilters<I extends ItemObject> = Record<string, SearchFilter<I>>;
|
export type SearchFilters<I extends ItemObject> = Record<string, SearchFilter<I>>;
|
||||||
@ -161,6 +163,7 @@ export interface ItemListLayoutStorage {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
selectedFilterNamespaces: IComputedValue<string[]>;
|
selectedFilterNamespaces: IComputedValue<string[]>;
|
||||||
itemListLayoutStorage: StorageLayer<ItemListLayoutStorage>;
|
itemListLayoutStorage: StorageLayer<ItemListLayoutStorage>;
|
||||||
|
pageFiltersStore: PageFiltersStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -197,7 +200,7 @@ class NonInjectedItemListLayout<I extends ItemObject, PreLoadStores extends bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
@computed get filters() {
|
@computed get filters() {
|
||||||
let { activeFilters } = pageFilters;
|
let { activeFilters } = this.props.pageFiltersStore;
|
||||||
const { searchFilters = [] } = this.props;
|
const { searchFilters = [] } = this.props;
|
||||||
|
|
||||||
if (searchFilters.length === 0) {
|
if (searchFilters.length === 0) {
|
||||||
@ -229,7 +232,7 @@ class NonInjectedItemListLayout<I extends ItemObject, PreLoadStores extends bool
|
|||||||
private filterCallbacks: ItemsFilters<I> = {
|
private filterCallbacks: ItemsFilters<I> = {
|
||||||
[FilterType.SEARCH]: items => {
|
[FilterType.SEARCH]: items => {
|
||||||
const { searchFilters = [] } = this.props;
|
const { searchFilters = [] } = this.props;
|
||||||
const search = pageFilters.getValues(FilterType.SEARCH)[0] || "";
|
const search = this.props.pageFiltersStore.getValues(FilterType.SEARCH)[0] || "";
|
||||||
|
|
||||||
if (search && searchFilters.length) {
|
if (search && searchFilters.length) {
|
||||||
const searchTexts = [search].map(normalizeText);
|
const searchTexts = [search].map(normalizeText);
|
||||||
@ -326,17 +329,14 @@ class NonInjectedItemListLayout<I extends ItemObject, PreLoadStores extends bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InjectedItemListLayout = withInjectables<Dependencies, ItemListLayoutProps<ItemObject, boolean>>(NonInjectedItemListLayout, {
|
export const ItemListLayout = withInjectables<Dependencies, ItemListLayoutProps<ItemObject, boolean>>(NonInjectedItemListLayout, {
|
||||||
getProps: (di, props) => ({
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
selectedFilterNamespaces: di.inject(selectedFilterNamespacesInjectable),
|
selectedFilterNamespaces: di.inject(selectedFilterNamespacesInjectable),
|
||||||
itemListLayoutStorage: di.inject(itemListLayoutStorageInjectable),
|
itemListLayoutStorage: di.inject(itemListLayoutStorageInjectable),
|
||||||
...props,
|
pageFiltersStore: di.inject(pageFiltersStoreInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
}) as <I extends ItemObject, PreLoadStores extends boolean = true>(props: ItemListLayoutProps<I, PreLoadStores>) => React.ReactElement;
|
||||||
|
|
||||||
export function ItemListLayout<I extends ItemObject, PreLoadStores extends boolean = true>(props: ItemListLayoutProps<I, PreLoadStores>) {
|
|
||||||
return <InjectedItemListLayout {...(props as never)} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyFilters<I extends ItemObject>(filters: ItemsFilter<I>[], items: I[]): I[] {
|
function applyFilters<I extends ItemObject>(filters: ItemsFilter<I>[], items: I[]): I[] {
|
||||||
if (!filters || !filters.length) {
|
if (!filters || !filters.length) {
|
||||||
|
|||||||
@ -1,85 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "./page-filters-list.scss";
|
|
||||||
import React from "react";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { Badge } from "../badge";
|
|
||||||
import { cssNames } from "../../utils";
|
|
||||||
import type { Filter } from "./page-filters.store";
|
|
||||||
import { pageFilters } from "./page-filters.store";
|
|
||||||
import { FilterIcon } from "./filter-icon";
|
|
||||||
import { Icon } from "../icon";
|
|
||||||
import { searchUrlParam } from "../input";
|
|
||||||
|
|
||||||
export interface PageFiltersListProps {
|
|
||||||
filters?: Filter[];
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class PageFiltersList extends React.Component<PageFiltersListProps> {
|
|
||||||
static defaultProps: PageFiltersListProps = {
|
|
||||||
get filters() {
|
|
||||||
return pageFilters.activeFilters;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
reset = () => pageFilters.reset();
|
|
||||||
remove = (filter: Filter) => {
|
|
||||||
pageFilters.removeFilter(filter);
|
|
||||||
searchUrlParam.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
renderContent() {
|
|
||||||
const { filters = [] } = this.props;
|
|
||||||
|
|
||||||
if (!filters.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="header flex gaps">
|
|
||||||
<span>Currently applied filters:</span>
|
|
||||||
<a onClick={this.reset} className="reset">
|
|
||||||
Reset
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="labels">
|
|
||||||
{filters.map(filter => {
|
|
||||||
const { value, type } = filter;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Badge
|
|
||||||
key={`${type}-${value}`}
|
|
||||||
title={type}
|
|
||||||
className={cssNames("Badge flex gaps filter align-center", type)}
|
|
||||||
label={(
|
|
||||||
<>
|
|
||||||
<FilterIcon type={type}/>
|
|
||||||
<span className="value">{value}</span>
|
|
||||||
<Icon
|
|
||||||
small
|
|
||||||
material="close"
|
|
||||||
onClick={() => this.remove(filter)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="PageFiltersList">
|
|
||||||
{this.renderContent()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./list.scss";
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { Badge } from "../../badge";
|
||||||
|
import { cssNames } from "../../../utils";
|
||||||
|
import type { Filter, PageFiltersStore } from "./store";
|
||||||
|
import { FilterIcon } from "../filter-icon";
|
||||||
|
import { Icon } from "../../icon";
|
||||||
|
import type { PageParam } from "../../../navigation";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import pageFiltersStoreInjectable from "./store.injectable";
|
||||||
|
import searchUrlPageParamInjectable from "../../input/search-url-page-param.injectable";
|
||||||
|
|
||||||
|
export interface PageFiltersListProps {
|
||||||
|
filters?: Filter[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
pageFiltersStore: PageFiltersStore;
|
||||||
|
searchUrlParam: PageParam<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedPageFiltersList = observer(({
|
||||||
|
pageFiltersStore,
|
||||||
|
searchUrlParam,
|
||||||
|
filters: rawFilters,
|
||||||
|
}: Dependencies & PageFiltersListProps) => {
|
||||||
|
const filters = rawFilters ?? pageFiltersStore.activeFilters;
|
||||||
|
|
||||||
|
const reset = () => pageFiltersStore.reset();
|
||||||
|
const remove = (filter: Filter) => {
|
||||||
|
pageFiltersStore.removeFilter(filter);
|
||||||
|
searchUrlParam.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
if (filters.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="header flex gaps">
|
||||||
|
<span>Currently applied filters:</span>
|
||||||
|
<a onClick={reset} className="reset">
|
||||||
|
Reset
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="labels">
|
||||||
|
{filters.map(filter => {
|
||||||
|
const { value, type } = filter;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
key={`${type}-${value}`}
|
||||||
|
title={type}
|
||||||
|
className={cssNames("Badge flex gaps filter align-center", type)}
|
||||||
|
label={(
|
||||||
|
<>
|
||||||
|
<FilterIcon type={type}/>
|
||||||
|
<span className="value">{value}</span>
|
||||||
|
<Icon
|
||||||
|
small
|
||||||
|
material="close"
|
||||||
|
onClick={() => remove(filter)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="PageFiltersList">
|
||||||
|
{renderContent()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PageFiltersList = withInjectables<Dependencies, PageFiltersListProps>(NonInjectedPageFiltersList, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
pageFiltersStore: di.inject(pageFiltersStoreInjectable),
|
||||||
|
searchUrlParam: di.inject(searchUrlPageParamInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import searchUrlPageParamInjectable from "../../input/search-url-page-param.injectable";
|
||||||
|
import { PageFiltersStore } from "./store";
|
||||||
|
|
||||||
|
const pageFiltersStoreInjectable = getInjectable({
|
||||||
|
id: "page-filters-store",
|
||||||
|
instantiate: (di) => new PageFiltersStore({
|
||||||
|
searchUrlParam: di.inject(searchUrlPageParamInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default pageFiltersStoreInjectable;
|
||||||
@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { computed, observable, reaction, makeObservable, action } from "mobx";
|
import { computed, observable, reaction, makeObservable, action } from "mobx";
|
||||||
import { autoBind } from "../../utils";
|
import type { PageParam } from "../../../navigation";
|
||||||
import { searchUrlParam } from "../input/search-input-url";
|
import { autoBind } from "../../../utils";
|
||||||
|
|
||||||
export enum FilterType {
|
export enum FilterType {
|
||||||
SEARCH = "search",
|
SEARCH = "search",
|
||||||
@ -16,6 +16,10 @@ export interface Filter {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
readonly searchUrlParam: PageParam<string>;
|
||||||
|
}
|
||||||
|
|
||||||
export class PageFiltersStore {
|
export class PageFiltersStore {
|
||||||
protected filters = observable.array<Filter>([], { deep: false });
|
protected filters = observable.array<Filter>([], { deep: false });
|
||||||
protected isDisabled = observable.map<FilterType, boolean>();
|
protected isDisabled = observable.map<FilterType, boolean>();
|
||||||
@ -24,7 +28,7 @@ export class PageFiltersStore {
|
|||||||
return this.filters.filter(filter => !this.isDisabled.get(filter.type));
|
return this.filters.filter(filter => !this.isDisabled.get(filter.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
autoBind(this);
|
autoBind(this);
|
||||||
|
|
||||||
@ -33,8 +37,8 @@ export class PageFiltersStore {
|
|||||||
|
|
||||||
protected syncWithGlobalSearch() {
|
protected syncWithGlobalSearch() {
|
||||||
const disposers = [
|
const disposers = [
|
||||||
reaction(() => this.getValues(FilterType.SEARCH)[0], search => searchUrlParam.set(search)),
|
reaction(() => this.getValues(FilterType.SEARCH)[0], search => this.dependencies.searchUrlParam.set(search)),
|
||||||
reaction(() => searchUrlParam.get(), search => {
|
reaction(() => this.dependencies.searchUrlParam.get(), search => {
|
||||||
const filter = this.getByType(FilterType.SEARCH);
|
const filter = this.getByType(FilterType.SEARCH);
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
@ -102,12 +106,10 @@ export class PageFiltersStore {
|
|||||||
@action
|
@action
|
||||||
reset() {
|
reset() {
|
||||||
if (this.isEnabled(FilterType.SEARCH)) {
|
if (this.isEnabled(FilterType.SEARCH)) {
|
||||||
searchUrlParam.clear();
|
this.dependencies.searchUrlParam.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.filters.length = 0;
|
this.filters.length = 0;
|
||||||
this.isDisabled.clear();
|
this.isDisabled.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pageFilters = new PageFiltersStore();
|
|
||||||
@ -11,7 +11,7 @@ import getDetailsUrlInjectable from "./get-details-url.injectable";
|
|||||||
* @param resetSelected If true then will reset the selected kube object (which object is highlighted generally)
|
* @param resetSelected If true then will reset the selected kube object (which object is highlighted generally)
|
||||||
* @default resetSelected true
|
* @default resetSelected true
|
||||||
*/
|
*/
|
||||||
export type ShowDetails = (selfLink: string, resetSelected?: boolean) => void;
|
export type ShowDetails = (selfLink: string | undefined, resetSelected?: boolean) => void;
|
||||||
|
|
||||||
const showDetailsInjectable = getInjectable({
|
const showDetailsInjectable = getInjectable({
|
||||||
id: "show-details",
|
id: "show-details",
|
||||||
@ -19,7 +19,7 @@ const showDetailsInjectable = getInjectable({
|
|||||||
const observableHistory = di.inject(observableHistoryInjectable);
|
const observableHistory = di.inject(observableHistoryInjectable);
|
||||||
const getDetailsUrl = di.inject(getDetailsUrlInjectable);
|
const getDetailsUrl = di.inject(getDetailsUrlInjectable);
|
||||||
|
|
||||||
return (selfLink, resetSelected = true) => {
|
return (selfLink = "", resetSelected = true) => {
|
||||||
observableHistory.merge({
|
observableHistory.merge({
|
||||||
search: getDetailsUrl(selfLink, resetSelected),
|
search: getDetailsUrl(selfLink, resetSelected),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,13 +2,16 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getActiveClusterEntity } from "../../../api/catalog-entity-registry";
|
|
||||||
|
|
||||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import getActiveClusterEntityInjectable from "../../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
|
||||||
const clusterInjectable = getInjectable({
|
const clusterInjectable = getInjectable({
|
||||||
id: "cluster",
|
id: "cluster",
|
||||||
instantiate: () => getActiveClusterEntity(),
|
instantiate: (di) => {
|
||||||
|
const getActiveClusterEntity = di.inject(getActiveClusterEntityInjectable);
|
||||||
|
|
||||||
|
return getActiveClusterEntity();
|
||||||
|
},
|
||||||
lifecycle: lifecycleEnum.transient,
|
lifecycle: lifecycleEnum.transient,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import asyncFn from "@async-fn/jest";
|
|||||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||||
|
|
||||||
import clusterInjectable from "./dependencies/cluster.injectable";
|
import clusterInjectable from "./dependencies/cluster.injectable";
|
||||||
import hideDetailsInjectable from "./dependencies/hide-details.injectable";
|
|
||||||
import type { DiRender } from "../test-utils/renderFor";
|
import type { DiRender } from "../test-utils/renderFor";
|
||||||
import { renderFor } from "../test-utils/renderFor";
|
import { renderFor } from "../test-utils/renderFor";
|
||||||
import type { Cluster } from "../../../common/cluster/cluster";
|
import type { Cluster } from "../../../common/cluster/cluster";
|
||||||
@ -26,6 +25,7 @@ import { computed } from "mobx";
|
|||||||
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||||
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||||
import createEditResourceTabInjectable from "../dock/edit-resource/edit-resource-tab.injectable";
|
import createEditResourceTabInjectable from "../dock/edit-resource/edit-resource-tab.injectable";
|
||||||
|
import hideDetailsInjectable from "../kube-detail-params/hide-details.injectable";
|
||||||
|
|
||||||
// TODO: Make tooltips free of side effects by making it deterministic
|
// TODO: Make tooltips free of side effects by making it deterministic
|
||||||
jest.mock("../tooltip");
|
jest.mock("../tooltip");
|
||||||
|
|||||||
@ -9,20 +9,25 @@ import React from "react";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { SidebarItem } from "./sidebar-item";
|
import { SidebarItem } from "./sidebar-item";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import { SidebarCluster } from "./sidebar-cluster";
|
import { SidebarCluster } from "./sidebar-cluster";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type { HierarchicalSidebarItem } from "./sidebar-items.injectable";
|
import type { HierarchicalSidebarItem } from "./sidebar-items.injectable";
|
||||||
import sidebarItemsInjectable from "./sidebar-items.injectable";
|
import sidebarItemsInjectable from "./sidebar-items.injectable";
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
sidebarItems: IComputedValue<HierarchicalSidebarItem[]>;
|
sidebarItems: IComputedValue<HierarchicalSidebarItem[]>;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NonInjectedSidebar = observer(({ sidebarItems }: Dependencies) => (
|
export const NonInjectedSidebar = observer(({
|
||||||
|
sidebarItems,
|
||||||
|
entityRegistry,
|
||||||
|
}: Dependencies) => (
|
||||||
<div className={cssNames("flex flex-col")} data-testid="cluster-sidebar">
|
<div className={cssNames("flex flex-col")} data-testid="cluster-sidebar">
|
||||||
<SidebarCluster clusterEntity={catalogEntityRegistry.activeEntity} />
|
<SidebarCluster clusterEntity={entityRegistry.activeEntity} />
|
||||||
|
|
||||||
<div className={`${styles.sidebarNav} sidebar-active-status`}>
|
<div className={`${styles.sidebarNav} sidebar-active-status`}>
|
||||||
{
|
{
|
||||||
@ -42,6 +47,7 @@ export const Sidebar = withInjectables<Dependencies>(NonInjectedSidebar, {
|
|||||||
getProps: (di, props) => ({
|
getProps: (di, props) => ({
|
||||||
...props,
|
...props,
|
||||||
sidebarItems: di.inject(sidebarItemsInjectable),
|
sidebarItems: di.inject(sidebarItemsInjectable),
|
||||||
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import createPageParamInjectable from "../../navigation/create-page-param.injectable";
|
||||||
|
|
||||||
|
const orderByUrlParamInjectable = getInjectable({
|
||||||
|
id: "order-by-url-param",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const createPageParam = di.inject(createPageParamInjectable);
|
||||||
|
|
||||||
|
return createPageParam({
|
||||||
|
name: "order",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default orderByUrlParamInjectable;
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import createPageParamInjectable from "../../navigation/create-page-param.injectable";
|
||||||
|
|
||||||
|
const sortByUrlParamInjectable = getInjectable({
|
||||||
|
id: "sort-by-url-param",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const createPageParam = di.inject(createPageParamInjectable);
|
||||||
|
|
||||||
|
return createPageParam({
|
||||||
|
name: "sort",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default sortByUrlParamInjectable;
|
||||||
@ -14,7 +14,7 @@ import type { TableHeadElem } from "./table-head";
|
|||||||
import { TableHead } from "./table-head";
|
import { TableHead } from "./table-head";
|
||||||
import type { TableCellElem } from "./table-cell";
|
import type { TableCellElem } from "./table-cell";
|
||||||
import { VirtualList } from "../virtual-list";
|
import { VirtualList } from "../virtual-list";
|
||||||
import { createPageParam } from "../../navigation";
|
import type { PageParam } from "../../navigation";
|
||||||
import { computed, makeObservable } from "mobx";
|
import { computed, makeObservable } from "mobx";
|
||||||
import { getSorted } from "./sorting";
|
import { getSorted } from "./sorting";
|
||||||
import type { TableModel } from "./table-model/table-model";
|
import type { TableModel } from "./table-model/table-model";
|
||||||
@ -22,6 +22,8 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
|||||||
import tableModelInjectable from "./table-model/table-model.injectable";
|
import tableModelInjectable from "./table-model/table-model.injectable";
|
||||||
import type { ItemObject } from "../../../common/item.store";
|
import type { ItemObject } from "../../../common/item.store";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
|
import orderByUrlParamInjectable from "./order-by-url-param.injectable";
|
||||||
|
import sortByUrlParamInjectable from "./sort-by-url-param.injectable";
|
||||||
|
|
||||||
export type TableSortBy = string;
|
export type TableSortBy = string;
|
||||||
export type TableOrderBy = "asc" | "desc";
|
export type TableOrderBy = "asc" | "desc";
|
||||||
@ -75,16 +77,10 @@ export interface TableProps<Item> extends React.DOMAttributes<HTMLDivElement> {
|
|||||||
renderRow?: (item: Item) => React.ReactElement<TableRowProps<Item>> | undefined | null;
|
renderRow?: (item: Item) => React.ReactElement<TableRowProps<Item>> | undefined | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sortByUrlParam = createPageParam({
|
|
||||||
name: "sort",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const orderByUrlParam = createPageParam({
|
|
||||||
name: "order",
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
model: TableModel;
|
model: TableModel;
|
||||||
|
sortByUrlParam: PageParam<string>;
|
||||||
|
orderByUrlParam: PageParam<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -178,8 +174,8 @@ class NonInjectedTable<Item extends ItemObject> extends React.Component<TablePro
|
|||||||
const { sortSyncWithUrl, onSort } = this.props;
|
const { sortSyncWithUrl, onSort } = this.props;
|
||||||
|
|
||||||
if (sortSyncWithUrl) {
|
if (sortSyncWithUrl) {
|
||||||
sortByUrlParam.set(sortBy);
|
this.props.sortByUrlParam.set(sortBy);
|
||||||
orderByUrlParam.set(orderBy);
|
this.props.orderByUrlParam.set(orderBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSort?.({ sortBy, orderBy });
|
onSort?.({ sortBy, orderBy });
|
||||||
@ -269,18 +265,12 @@ class NonInjectedTable<Item extends ItemObject> extends React.Component<TablePro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InjectedTable = withInjectables<Dependencies, TableProps<any>>(
|
export const Table = withInjectables<Dependencies, TableProps<ItemObject>>(NonInjectedTable, {
|
||||||
NonInjectedTable,
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
{
|
model: di.inject(tableModelInjectable),
|
||||||
getProps: (di, props) => ({
|
orderByUrlParam: di.inject(orderByUrlParamInjectable),
|
||||||
model: di.inject(tableModelInjectable),
|
sortByUrlParam: di.inject(sortByUrlParamInjectable),
|
||||||
...props,
|
}),
|
||||||
}),
|
}) as <Item>(props: TableProps<Item>) => React.ReactElement;
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export function Table<Item>(props: TableProps<Item>) {
|
|
||||||
return <InjectedTable {...props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
|
||||||
|
import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token";
|
||||||
|
import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||||
|
import type { LensRendererExtensionDependencies } from "../../extensions/lens-extension-set-dependencies";
|
||||||
|
import catalogEntityRegistryInjectable from "../api/catalog/entity/registry.injectable";
|
||||||
|
import getExtensionPageParametersInjectable from "../routes/get-extension-page-parameters.injectable";
|
||||||
|
import navigateToRouteInjectable from "../routes/navigate-to-route.injectable";
|
||||||
|
import routesInjectable from "../routes/routes.injectable";
|
||||||
|
|
||||||
|
const createExtensionInstanceInjectable = getInjectable({
|
||||||
|
id: "create-extension-instance",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const deps: LensRendererExtensionDependencies = {
|
||||||
|
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||||
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
|
fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable),
|
||||||
|
getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable),
|
||||||
|
navigateToRoute: di.inject(navigateToRouteInjectable),
|
||||||
|
routes: di.inject(routesInjectable),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (ExtensionClass, extension) => {
|
||||||
|
const instance = new ExtensionClass(extension);
|
||||||
|
|
||||||
|
(instance as unknown as { dependencies: LensRendererExtensionDependencies }).dependencies = deps;
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: createExtensionInstanceInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createExtensionInstanceInjectable;
|
||||||
@ -5,7 +5,7 @@
|
|||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { initClusterFrame } from "./init-cluster-frame";
|
import { initClusterFrame } from "./init-cluster-frame";
|
||||||
import extensionLoaderInjectable from "../../../../extensions/extension-loader/extension-loader.injectable";
|
import extensionLoaderInjectable from "../../../../extensions/extension-loader/extension-loader.injectable";
|
||||||
import catalogEntityRegistryInjectable from "../../../api/catalog-entity-registry/catalog-entity-registry.injectable";
|
import catalogEntityRegistryInjectable from "../../../api/catalog/entity/registry.injectable";
|
||||||
import frameRoutingIdInjectable from "./frame-routing-id/frame-routing-id.injectable";
|
import frameRoutingIdInjectable from "./frame-routing-id/frame-routing-id.injectable";
|
||||||
import hostedClusterInjectable from "../../../../common/cluster-store/hosted-cluster.injectable";
|
import hostedClusterInjectable from "../../../../common/cluster-store/hosted-cluster.injectable";
|
||||||
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
|
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||||
import type { CatalogEntityRegistry } from "../../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
|
||||||
import logger from "../../../../main/logger";
|
import logger from "../../../../main/logger";
|
||||||
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||||
import { Notifications } from "../../../components/notifications";
|
import { Notifications } from "../../../components/notifications";
|
||||||
@ -51,7 +51,7 @@ export const initClusterFrame = ({
|
|||||||
// Only load the extensions once the catalog has been populated.
|
// Only load the extensions once the catalog has been populated.
|
||||||
// Note that the Catalog might still have unprocessed entities until the extensions are fully loaded.
|
// Note that the Catalog might still have unprocessed entities until the extensions are fully loaded.
|
||||||
when(
|
when(
|
||||||
() => catalogEntityRegistry.items.length > 0,
|
() => catalogEntityRegistry.items.get().length > 0,
|
||||||
() =>
|
() =>
|
||||||
loadExtensions(() => catalogEntityRegistry.activeEntity as KubernetesCluster),
|
loadExtensions(() => catalogEntityRegistry.activeEntity as KubernetesCluster),
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,33 +8,19 @@ import extensionLoaderInjectable from "../../../../extensions/extension-loader/e
|
|||||||
import ipcRendererInjectable from "../../../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
import ipcRendererInjectable from "../../../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||||
import bindProtocolAddRouteHandlersInjectable from "../../../protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable";
|
import bindProtocolAddRouteHandlersInjectable from "../../../protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable";
|
||||||
import lensProtocolRouterRendererInjectable from "../../../protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable";
|
import lensProtocolRouterRendererInjectable from "../../../protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable";
|
||||||
import catalogEntityRegistryInjectable from "../../../api/catalog-entity-registry/catalog-entity-registry.injectable";
|
import catalogEntityRegistryInjectable from "../../../api/catalog/entity/registry.injectable";
|
||||||
import registerIpcListenersInjectable from "../../../ipc/register-ipc-listeners.injectable";
|
import registerIpcListenersInjectable from "../../../ipc/register-ipc-listeners.injectable";
|
||||||
|
|
||||||
const initRootFrameInjectable = getInjectable({
|
const initRootFrameInjectable = getInjectable({
|
||||||
id: "init-root-frame",
|
id: "init-root-frame",
|
||||||
|
instantiate: (di) => initRootFrame({
|
||||||
instantiate: (di) => {
|
loadExtensions: di.inject(extensionLoaderInjectable).loadOnClusterManagerRenderer,
|
||||||
const extensionLoader = di.inject(extensionLoaderInjectable);
|
registerIpcListeners: di.inject(registerIpcListenersInjectable),
|
||||||
|
ipcRenderer: di.inject(ipcRendererInjectable),
|
||||||
return initRootFrame({
|
bindProtocolAddRouteHandlers: di.inject(bindProtocolAddRouteHandlersInjectable),
|
||||||
loadExtensions: extensionLoader.loadOnClusterManagerRenderer,
|
lensProtocolRouterRenderer: di.inject(lensProtocolRouterRendererInjectable),
|
||||||
|
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
registerIpcListeners: di.inject(registerIpcListenersInjectable),
|
}),
|
||||||
|
|
||||||
ipcRenderer: di.inject(ipcRendererInjectable),
|
|
||||||
|
|
||||||
bindProtocolAddRouteHandlers: di.inject(
|
|
||||||
bindProtocolAddRouteHandlersInjectable,
|
|
||||||
),
|
|
||||||
|
|
||||||
lensProtocolRouterRenderer: di.inject(
|
|
||||||
lensProtocolRouterRendererInjectable,
|
|
||||||
),
|
|
||||||
|
|
||||||
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default initRootFrameInjectable;
|
export default initRootFrameInjectable;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { delay } from "../../../../common/utils";
|
|||||||
import { broadcastMessage } from "../../../../common/ipc";
|
import { broadcastMessage } from "../../../../common/ipc";
|
||||||
import logger from "../../../../common/logger";
|
import logger from "../../../../common/logger";
|
||||||
import type { ExtensionLoading } from "../../../../extensions/extension-loader";
|
import type { ExtensionLoading } from "../../../../extensions/extension-loader";
|
||||||
import type { CatalogEntityRegistry } from "../../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
|
||||||
import { bundledExtensionsLoaded } from "../../../../common/ipc/extension-handling";
|
import { bundledExtensionsLoaded } from "../../../../common/ipc/extension-handling";
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,8 @@ import registerIpcChannelListenerInjectable from "./app-paths/get-value-from-reg
|
|||||||
import focusWindowInjectable from "./ipc-channel-listeners/focus-window.injectable";
|
import focusWindowInjectable from "./ipc-channel-listeners/focus-window.injectable";
|
||||||
import extensionsStoreInjectable from "../extensions/extensions-store/extensions-store.injectable";
|
import extensionsStoreInjectable from "../extensions/extensions-store/extensions-store.injectable";
|
||||||
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
|
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
|
||||||
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||||
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/create-extension-instance/file-system-provisioner-store/file-system-provisioner-store";
|
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
|
||||||
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
|
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
|
||||||
import type { ClusterStore } from "../common/cluster-store/cluster-store";
|
import type { ClusterStore } from "../common/cluster-store/cluster-store";
|
||||||
import type { Cluster } from "../common/cluster/cluster";
|
import type { Cluster } from "../common/cluster/cluster";
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
import { asLegacyGlobalFunctionForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
import { asLegacyGlobalFunctionForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||||
import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||||
import createPageParamInjectable from "./create-page-param.injectable";
|
|
||||||
import matchRouteInjectable from "./match-route.injectable";
|
import matchRouteInjectable from "./match-route.injectable";
|
||||||
import navigateInjectable from "./navigate.injectable";
|
import navigateInjectable from "./navigate.injectable";
|
||||||
import observableHistoryInjectable from "./observable-history.injectable";
|
import observableHistoryInjectable from "./observable-history.injectable";
|
||||||
@ -22,11 +21,6 @@ export const navigation = asLegacyGlobalForExtensionApi(observableHistoryInjecta
|
|||||||
*/
|
*/
|
||||||
export const navigate = asLegacyGlobalFunctionForExtensionApi(navigateInjectable);
|
export const navigate = asLegacyGlobalFunctionForExtensionApi(navigateInjectable);
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use `di.inject(createPageParamInjectable)` instead
|
|
||||||
*/
|
|
||||||
export const createPageParam = asLegacyGlobalFunctionForExtensionApi(createPageParamInjectable);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use `di.inject(matchRouteInjectable)` instead
|
* @deprecated use `di.inject(matchRouteInjectable)` instead
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -12,25 +12,22 @@ import navigateToExtensionsInjectable from "../../../common/front-end-routing/ro
|
|||||||
import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
||||||
import navigateToClusterViewInjectable from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable";
|
import navigateToClusterViewInjectable from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable";
|
||||||
import navigateToPreferenceTabIdInjectable from "./navigate-to-preference-tab-id.injectable";
|
import navigateToPreferenceTabIdInjectable from "./navigate-to-preference-tab-id.injectable";
|
||||||
|
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
|
|
||||||
const bindProtocolAddRouteHandlersInjectable = getInjectable({
|
const bindProtocolAddRouteHandlersInjectable = getInjectable({
|
||||||
id: "bind-protocol-add-route-handlers",
|
id: "bind-protocol-add-route-handlers",
|
||||||
|
|
||||||
instantiate: (di) =>
|
instantiate: (di) => bindProtocolAddRouteHandlers({
|
||||||
bindProtocolAddRouteHandlers({
|
attemptInstallByInfo: di.inject(attemptInstallByInfoInjectable),
|
||||||
attemptInstallByInfo: di.inject(attemptInstallByInfoInjectable),
|
lensProtocolRouterRenderer: di.inject(lensProtocolRouterRendererInjectable ),
|
||||||
|
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||||
lensProtocolRouterRenderer: di.inject(
|
navigateToAddCluster: di.inject(navigateToAddClusterInjectable),
|
||||||
lensProtocolRouterRendererInjectable,
|
navigateToExtensions: di.inject(navigateToExtensionsInjectable),
|
||||||
),
|
navigateToEntitySettings: di.inject(navigateToEntitySettingsInjectable),
|
||||||
|
navigateToClusterView: di.inject(navigateToClusterViewInjectable),
|
||||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
navigateToPreferenceTabId: di.inject(navigateToPreferenceTabIdInjectable),
|
||||||
navigateToAddCluster: di.inject(navigateToAddClusterInjectable),
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
navigateToExtensions: di.inject(navigateToExtensionsInjectable),
|
}),
|
||||||
navigateToEntitySettings: di.inject(navigateToEntitySettingsInjectable),
|
|
||||||
navigateToClusterView: di.inject(navigateToClusterViewInjectable),
|
|
||||||
navigateToPreferenceTabId: di.inject(navigateToPreferenceTabIdInjectable),
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default bindProtocolAddRouteHandlersInjectable;
|
export default bindProtocolAddRouteHandlersInjectable;
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { LensProtocolRouterRenderer } from "../lens-protocol-router-renderer/lens-protocol-router-renderer";
|
import type { LensProtocolRouterRenderer } from "../lens-protocol-router-renderer/lens-protocol-router-renderer";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||||
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||||
import {
|
import {
|
||||||
EXTENSION_NAME_MATCH,
|
EXTENSION_NAME_MATCH,
|
||||||
@ -30,118 +30,112 @@ interface Dependencies {
|
|||||||
navigateToEntitySettings: NavigateToEntitySettings;
|
navigateToEntitySettings: NavigateToEntitySettings;
|
||||||
navigateToClusterView: NavigateToClusterView;
|
navigateToClusterView: NavigateToClusterView;
|
||||||
navigateToPreferenceTabId: (tabId: string) => void;
|
navigateToPreferenceTabId: (tabId: string) => void;
|
||||||
|
entityRegistry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const bindProtocolAddRouteHandlers =
|
export const bindProtocolAddRouteHandlers = ({
|
||||||
({ attemptInstallByInfo, lensProtocolRouterRenderer, navigateToCatalog, navigateToAddCluster, navigateToExtensions, navigateToEntitySettings, navigateToClusterView, navigateToPreferenceTabId }: Dependencies) =>
|
attemptInstallByInfo,
|
||||||
() => {
|
lensProtocolRouterRenderer,
|
||||||
lensProtocolRouterRenderer
|
navigateToCatalog,
|
||||||
.addInternalHandler("/preferences", ({ search: { highlight: tabId }}) => {
|
navigateToAddCluster,
|
||||||
if (tabId) {
|
navigateToExtensions,
|
||||||
navigateToPreferenceTabId(tabId);
|
navigateToEntitySettings,
|
||||||
}
|
navigateToClusterView,
|
||||||
})
|
navigateToPreferenceTabId,
|
||||||
.addInternalHandler("/", ({ tail }) => {
|
entityRegistry,
|
||||||
if (tail) {
|
}: Dependencies) => () => {
|
||||||
Notifications.shortInfo(
|
lensProtocolRouterRenderer
|
||||||
<p>
|
.addInternalHandler("/preferences", ({ search: { highlight: tabId }}) => {
|
||||||
{"Unknown Action for "}
|
if (tabId) {
|
||||||
<code>
|
navigateToPreferenceTabId(tabId);
|
||||||
lens://app/
|
}
|
||||||
{tail}
|
})
|
||||||
</code>
|
.addInternalHandler("/", ({ tail }) => {
|
||||||
. Are you on the latest version?
|
if (tail) {
|
||||||
</p>,
|
Notifications.shortInfo(
|
||||||
);
|
<p>
|
||||||
}
|
{"Unknown Action for "}
|
||||||
|
<code>
|
||||||
navigateToCatalog();
|
lens://app/
|
||||||
})
|
{tail}
|
||||||
.addInternalHandler("/landing", () => {
|
</code>
|
||||||
navigateToCatalog();
|
. Are you on the latest version?
|
||||||
})
|
</p>,
|
||||||
.addInternalHandler(
|
|
||||||
"/landing/view/:group/:kind",
|
|
||||||
({ pathname: { group, kind }}) => {
|
|
||||||
navigateToCatalog({ group, kind });
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.addInternalHandler("/cluster", () => {
|
|
||||||
navigateToAddCluster();
|
|
||||||
})
|
|
||||||
.addInternalHandler(
|
|
||||||
"/entity/:entityId/settings",
|
|
||||||
({ pathname: { entityId }}) => {
|
|
||||||
assert(entityId);
|
|
||||||
const entity = catalogEntityRegistry.getById(entityId);
|
|
||||||
|
|
||||||
if (entity) {
|
|
||||||
navigateToEntitySettings(entityId);
|
|
||||||
} else {
|
|
||||||
Notifications.shortInfo(
|
|
||||||
<p>
|
|
||||||
{"Unknown catalog entity "}
|
|
||||||
<code>{entityId}</code>
|
|
||||||
.
|
|
||||||
</p>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
// Handlers below are deprecated and only kept for backward compact purposes
|
|
||||||
.addInternalHandler(
|
|
||||||
"/cluster/:clusterId",
|
|
||||||
({ pathname: { clusterId }}) => {
|
|
||||||
assert(clusterId);
|
|
||||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
|
||||||
|
|
||||||
if (cluster) {
|
|
||||||
navigateToClusterView(clusterId);
|
|
||||||
} else {
|
|
||||||
Notifications.shortInfo(
|
|
||||||
<p>
|
|
||||||
{"Unknown catalog entity "}
|
|
||||||
<code>{clusterId}</code>
|
|
||||||
.
|
|
||||||
</p>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.addInternalHandler(
|
|
||||||
"/cluster/:clusterId/settings",
|
|
||||||
({ pathname: { clusterId }}) => {
|
|
||||||
assert(clusterId);
|
|
||||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
|
||||||
|
|
||||||
if (cluster) {
|
|
||||||
navigateToEntitySettings(clusterId);
|
|
||||||
} else {
|
|
||||||
Notifications.shortInfo(
|
|
||||||
<p>
|
|
||||||
{"Unknown catalog entity "}
|
|
||||||
<code>{clusterId}</code>
|
|
||||||
.
|
|
||||||
</p>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.addInternalHandler("/extensions", () => {
|
|
||||||
navigateToExtensions();
|
|
||||||
})
|
|
||||||
.addInternalHandler(
|
|
||||||
`/extensions/install${LensProtocolRouter.ExtensionUrlSchema}`,
|
|
||||||
({ pathname, search: { version }}) => {
|
|
||||||
const name = [
|
|
||||||
pathname[EXTENSION_PUBLISHER_MATCH],
|
|
||||||
pathname[EXTENSION_NAME_MATCH],
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join("/");
|
|
||||||
|
|
||||||
navigateToExtensions();
|
|
||||||
attemptInstallByInfo({ name, version, requireConfirmation: true });
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
navigateToCatalog();
|
||||||
|
})
|
||||||
|
.addInternalHandler("/landing", () => {
|
||||||
|
navigateToCatalog();
|
||||||
|
})
|
||||||
|
.addInternalHandler("/landing/view/:group/:kind", ({ pathname: { group, kind }}) => {
|
||||||
|
navigateToCatalog({ group, kind });
|
||||||
|
})
|
||||||
|
.addInternalHandler("/cluster", () => {
|
||||||
|
navigateToAddCluster();
|
||||||
|
})
|
||||||
|
.addInternalHandler("/entity/:entityId/settings", ({ pathname: { entityId }}) => {
|
||||||
|
assert(entityId);
|
||||||
|
const entity = entityRegistry.getById(entityId);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
navigateToEntitySettings(entityId);
|
||||||
|
} else {
|
||||||
|
Notifications.shortInfo(
|
||||||
|
<p>
|
||||||
|
{"Unknown catalog entity "}
|
||||||
|
<code>{entityId}</code>
|
||||||
|
.
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Handlers below are deprecated and only kept for backward compact purposes
|
||||||
|
.addInternalHandler("/cluster/:clusterId", ({ pathname: { clusterId }}) => {
|
||||||
|
assert(clusterId);
|
||||||
|
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||||
|
|
||||||
|
if (cluster) {
|
||||||
|
navigateToClusterView(clusterId);
|
||||||
|
} else {
|
||||||
|
Notifications.shortInfo(
|
||||||
|
<p>
|
||||||
|
{"Unknown catalog entity "}
|
||||||
|
<code>{clusterId}</code>
|
||||||
|
.
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addInternalHandler("/cluster/:clusterId/settings", ({ pathname: { clusterId }}) => {
|
||||||
|
assert(clusterId);
|
||||||
|
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||||
|
|
||||||
|
if (cluster) {
|
||||||
|
navigateToEntitySettings(clusterId);
|
||||||
|
} else {
|
||||||
|
Notifications.shortInfo(
|
||||||
|
<p>
|
||||||
|
{"Unknown catalog entity "}
|
||||||
|
<code>{clusterId}</code>
|
||||||
|
.
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addInternalHandler("/extensions", () => {
|
||||||
|
navigateToExtensions();
|
||||||
|
})
|
||||||
|
.addInternalHandler(`/extensions/install${LensProtocolRouter.ExtensionUrlSchema}`, ({ pathname, search: { version }}) => {
|
||||||
|
const name = [
|
||||||
|
pathname[EXTENSION_PUBLISHER_MATCH],
|
||||||
|
pathname[EXTENSION_NAME_MATCH],
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join("/");
|
||||||
|
|
||||||
|
navigateToExtensions();
|
||||||
|
attemptInstallByInfo({ name, version, requireConfirmation: true });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -7,10 +7,11 @@ import { pipeline } from "@ogre-tools/fp";
|
|||||||
import type { PageParamInit } from "../navigation";
|
import type { PageParamInit } from "../navigation";
|
||||||
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
||||||
import type { PageRegistration } from "../../extensions/registries";
|
import type { PageRegistration } from "../../extensions/registries";
|
||||||
import { fromPairs, map } from "lodash/fp";
|
import { map } from "lodash/fp";
|
||||||
import createPageParamInjectable from "../navigation/create-page-param.injectable";
|
import createPageParamInjectable from "../navigation/create-page-param.injectable";
|
||||||
|
import { object } from "../utils";
|
||||||
|
|
||||||
interface InstantiationParameter {
|
export interface ExtensionPageParametersInstantiationParam {
|
||||||
extension: LensRendererExtension;
|
extension: LensRendererExtension;
|
||||||
registration: PageRegistration;
|
registration: PageRegistration;
|
||||||
}
|
}
|
||||||
@ -18,7 +19,7 @@ interface InstantiationParameter {
|
|||||||
const extensionPageParametersInjectable = getInjectable({
|
const extensionPageParametersInjectable = getInjectable({
|
||||||
id: "extension-page-parameters",
|
id: "extension-page-parameters",
|
||||||
|
|
||||||
instantiate: (di, { registration }: InstantiationParameter) => {
|
instantiate: (di, { registration }: ExtensionPageParametersInstantiationParam) => {
|
||||||
const createPageParam = di.inject(createPageParamInjectable);
|
const createPageParam = di.inject(createPageParamInjectable);
|
||||||
|
|
||||||
return pipeline(
|
return pipeline(
|
||||||
@ -30,15 +31,15 @@ const extensionPageParametersInjectable = getInjectable({
|
|||||||
? convertStringToPageParamInit(key, value)
|
? convertStringToPageParamInit(key, value)
|
||||||
: convertPartialPageParamInitToFull(key, value),
|
: convertPartialPageParamInitToFull(key, value),
|
||||||
]),
|
]),
|
||||||
map(([key, value]) => [key, createPageParam(value)]),
|
map(([key, value]) => [key, createPageParam(value)] as const),
|
||||||
fromPairs,
|
object.fromEntries,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
lifecycle: lifecycleEnum.keyedSingleton({
|
lifecycle: lifecycleEnum.keyedSingleton({
|
||||||
getInstanceKey: (
|
getInstanceKey: (
|
||||||
di,
|
di,
|
||||||
{ extension, registration }: InstantiationParameter,
|
{ extension, registration }: ExtensionPageParametersInstantiationParam,
|
||||||
) => `${extension.sanitizedExtensionId}-${registration?.id}`,
|
) => `${extension.sanitizedExtensionId}-${registration?.id}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user