mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Release/v5.3.3 (#4548)
Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com> Co-authored-by: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Co-authored-by: Mario Sarcher <mario@sarcher.de>
This commit is contained in:
parent
e79e8eb76c
commit
0a6bafc1be
@ -3,7 +3,7 @@
|
|||||||
"productName": "OpenLens",
|
"productName": "OpenLens",
|
||||||
"description": "OpenLens - Open Source IDE for Kubernetes",
|
"description": "OpenLens - Open Source IDE for Kubernetes",
|
||||||
"homepage": "https://github.com/lensapp/lens",
|
"homepage": "https://github.com/lensapp/lens",
|
||||||
"version": "5.3.2",
|
"version": "5.3.3",
|
||||||
"main": "static/build/main.js",
|
"main": "static/build/main.js",
|
||||||
"copyright": "© 2021 OpenLens Authors",
|
"copyright": "© 2021 OpenLens Authors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -131,6 +131,11 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rpm": {
|
||||||
|
"fpm": [
|
||||||
|
"--rpm-rpmbuild-define=%define _build_id_links none"
|
||||||
|
]
|
||||||
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
"hardenedRuntime": true,
|
"hardenedRuntime": true,
|
||||||
"gatekeeperAssess": false,
|
"gatekeeperAssess": false,
|
||||||
@ -380,7 +385,6 @@
|
|||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^3.11.2",
|
||||||
"webpack-node-externals": "^1.7.2",
|
"webpack-node-externals": "^1.7.2",
|
||||||
"what-input": "^5.2.10",
|
|
||||||
"xterm": "^4.14.1",
|
"xterm": "^4.14.1",
|
||||||
"xterm-addon-fit": "^0.5.0"
|
"xterm-addon-fit": "^0.5.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,7 +78,17 @@ export class AppPaths {
|
|||||||
|
|
||||||
app.setPath("userData", path.join(app.getPath("appData"), app.getName()));
|
app.setPath("userData", path.join(app.getPath("appData"), app.getName()));
|
||||||
|
|
||||||
AppPaths.paths.set(fromEntries(pathNames.map(pathName => [pathName, app.getPath(pathName)])));
|
const getPath = (pathName: PathName) => {
|
||||||
|
try {
|
||||||
|
return app.getPath(pathName);
|
||||||
|
} catch {
|
||||||
|
logger.debug(`[APP-PATHS] No path found for ${pathName}`);
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AppPaths.paths.set(fromEntries(pathNames.map(pathName => [pathName, getPath(pathName)] as const).filter(([, path]) => path)));
|
||||||
ipcMain.handle(AppPaths.ipcChannel, () => toJS(AppPaths.paths.get()));
|
ipcMain.handle(AppPaths.ipcChannel, () => toJS(AppPaths.paths.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,12 @@ import { KubeObject } from "../kube-object";
|
|||||||
import AbortController from "abort-controller";
|
import AbortController from "abort-controller";
|
||||||
import { delay } from "../../utils/delay";
|
import { delay } from "../../utils/delay";
|
||||||
import { PassThrough } from "stream";
|
import { PassThrough } from "stream";
|
||||||
|
import { ApiManager, apiManager } from "../api-manager";
|
||||||
|
import { Ingress, Pod } from "../endpoints";
|
||||||
|
|
||||||
|
jest.mock("../api-manager");
|
||||||
|
|
||||||
|
const mockApiManager = apiManager as jest.Mocked<ApiManager>;
|
||||||
|
|
||||||
class TestKubeObject extends KubeObject {
|
class TestKubeObject extends KubeObject {
|
||||||
static kind = "Pod";
|
static kind = "Pod";
|
||||||
@ -33,7 +39,11 @@ class TestKubeObject extends KubeObject {
|
|||||||
static apiBase = "/api/v1/pods";
|
static apiBase = "/api/v1/pods";
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestKubeApi extends KubeApi<TestKubeObject> { }
|
class TestKubeApi extends KubeApi<TestKubeObject> {
|
||||||
|
public async checkPreferredVersion() {
|
||||||
|
return super.checkPreferredVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe("forRemoteCluster", () => {
|
describe("forRemoteCluster", () => {
|
||||||
it("builds api client for KubeObject", async () => {
|
it("builds api client for KubeObject", async () => {
|
||||||
@ -184,6 +194,94 @@ describe("KubeApi", () => {
|
|||||||
expect(kubeApi.apiGroup).toEqual("extensions");
|
expect(kubeApi.apiGroup).toEqual("extensions");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("checkPreferredVersion", () => {
|
||||||
|
it("registers with apiManager if checkPreferredVersion changes apiVersionPreferred", async () => {
|
||||||
|
expect.hasAssertions();
|
||||||
|
|
||||||
|
const api = new TestKubeApi({
|
||||||
|
objectConstructor: Ingress,
|
||||||
|
checkPreferredVersion: true,
|
||||||
|
fallbackApiBases: ["/apis/extensions/v1beta1/ingresses"],
|
||||||
|
request: {
|
||||||
|
get: jest.fn()
|
||||||
|
.mockImplementationOnce((path: string) => {
|
||||||
|
expect(path).toBe("/apis/networking.k8s.io/v1");
|
||||||
|
|
||||||
|
throw new Error("no");
|
||||||
|
})
|
||||||
|
.mockImplementationOnce((path: string) => {
|
||||||
|
expect(path).toBe("/apis/extensions/v1beta1");
|
||||||
|
|
||||||
|
return {
|
||||||
|
resources: [
|
||||||
|
{
|
||||||
|
name: "ingresses",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.mockImplementationOnce((path: string) => {
|
||||||
|
expect(path).toBe("/apis/extensions");
|
||||||
|
|
||||||
|
return {
|
||||||
|
preferredVersion: {
|
||||||
|
version: "v1beta1",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.checkPreferredVersion();
|
||||||
|
|
||||||
|
expect(api.apiVersionPreferred).toBe("v1beta1");
|
||||||
|
expect(mockApiManager.registerApi).toBeCalledWith("/apis/extensions/v1beta1/ingresses", expect.anything());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("registers with apiManager if checkPreferredVersion changes apiVersionPreferred with non-grouped apis", async () => {
|
||||||
|
expect.hasAssertions();
|
||||||
|
|
||||||
|
const api = new TestKubeApi({
|
||||||
|
objectConstructor: Pod,
|
||||||
|
checkPreferredVersion: true,
|
||||||
|
fallbackApiBases: ["/api/v1beta1/pods"],
|
||||||
|
request: {
|
||||||
|
get: jest.fn()
|
||||||
|
.mockImplementationOnce((path: string) => {
|
||||||
|
expect(path).toBe("/api/v1");
|
||||||
|
|
||||||
|
throw new Error("no");
|
||||||
|
})
|
||||||
|
.mockImplementationOnce((path: string) => {
|
||||||
|
expect(path).toBe("/api/v1beta1");
|
||||||
|
|
||||||
|
return {
|
||||||
|
resources: [
|
||||||
|
{
|
||||||
|
name: "pods",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.mockImplementationOnce((path: string) => {
|
||||||
|
expect(path).toBe("/api");
|
||||||
|
|
||||||
|
return {
|
||||||
|
preferredVersion: {
|
||||||
|
version: "v1beta1",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
} as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.checkPreferredVersion();
|
||||||
|
|
||||||
|
expect(api.apiVersionPreferred).toBe("v1beta1");
|
||||||
|
expect(mockApiManager.registerApi).toBeCalledWith("/api/v1beta1/pods", expect.anything());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("patch", () => {
|
describe("patch", () => {
|
||||||
let api: TestKubeApi;
|
let api: TestKubeApi;
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ export interface IKubeApiLinkRef {
|
|||||||
apiPrefix?: string;
|
apiPrefix?: string;
|
||||||
apiVersion: string;
|
apiVersion: string;
|
||||||
resource: string;
|
resource: string;
|
||||||
name: string;
|
name?: string;
|
||||||
namespace?: string;
|
namespace?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,15 +145,18 @@ function _parseKubeApi(path: string): IKubeApiParsed {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createKubeApiURL(ref: IKubeApiLinkRef): string {
|
export function createKubeApiURL({ apiPrefix = "/apis", resource, apiVersion, name, namespace }: IKubeApiLinkRef): string {
|
||||||
const { apiPrefix = "/apis", resource, apiVersion, name } = ref;
|
const parts = [apiPrefix, apiVersion];
|
||||||
let { namespace } = ref;
|
|
||||||
|
|
||||||
if (namespace) {
|
if (namespace) {
|
||||||
namespace = `namespaces/${namespace}`;
|
parts.push("namespaces", namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [apiPrefix, apiVersion, namespace, resource, name]
|
parts.push(resource);
|
||||||
.filter(v => v)
|
|
||||||
.join("/");
|
if (name) {
|
||||||
|
parts.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join("/");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,9 +38,14 @@ import AbortController from "abort-controller";
|
|||||||
import { Agent, AgentOptions } from "https";
|
import { Agent, AgentOptions } from "https";
|
||||||
import type { Patch } from "rfc6902";
|
import type { Patch } from "rfc6902";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options used for creating a `KubeApi`
|
||||||
|
*/
|
||||||
export interface IKubeApiOptions<T extends KubeObject> {
|
export interface IKubeApiOptions<T extends KubeObject> {
|
||||||
/**
|
/**
|
||||||
* base api-path for listing all resources, e.g. "/api/v1/pods"
|
* base api-path for listing all resources, e.g. "/api/v1/pods"
|
||||||
|
*
|
||||||
|
* If not specified then will be the one on the `objectConstructor`
|
||||||
*/
|
*/
|
||||||
apiBase?: string;
|
apiBase?: string;
|
||||||
|
|
||||||
@ -52,11 +57,33 @@ export interface IKubeApiOptions<T extends KubeObject> {
|
|||||||
*/
|
*/
|
||||||
fallbackApiBases?: string[];
|
fallbackApiBases?: string[];
|
||||||
|
|
||||||
objectConstructor: KubeObjectConstructor<T>;
|
/**
|
||||||
request?: KubeJsonApi;
|
* If `true` then will check all declared apiBases against the kube api server
|
||||||
isNamespaced?: boolean;
|
* for the first accepted one.
|
||||||
kind?: string;
|
*/
|
||||||
checkPreferredVersion?: boolean;
|
checkPreferredVersion?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor for the kube objects returned from the API
|
||||||
|
*/
|
||||||
|
objectConstructor: KubeObjectConstructor<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The api instance to use for making requests
|
||||||
|
*
|
||||||
|
* @default apiKube
|
||||||
|
*/
|
||||||
|
request?: KubeJsonApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated should be specified by `objectConstructor`
|
||||||
|
*/
|
||||||
|
isNamespaced?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated should be specified by `objectConstructor`
|
||||||
|
*/
|
||||||
|
kind?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IKubeApiQueryParams {
|
export interface IKubeApiQueryParams {
|
||||||
@ -249,11 +276,11 @@ export interface DeleteResourceDescriptor extends ResourceDescriptor {
|
|||||||
|
|
||||||
export class KubeApi<T extends KubeObject> {
|
export class KubeApi<T extends KubeObject> {
|
||||||
readonly kind: string;
|
readonly kind: string;
|
||||||
readonly apiBase: string;
|
|
||||||
readonly apiPrefix: string;
|
|
||||||
readonly apiGroup: string;
|
|
||||||
readonly apiVersion: string;
|
readonly apiVersion: string;
|
||||||
readonly apiVersionPreferred?: string;
|
apiBase: string;
|
||||||
|
apiPrefix: string;
|
||||||
|
apiGroup: string;
|
||||||
|
apiVersionPreferred?: string;
|
||||||
readonly apiResource: string;
|
readonly apiResource: string;
|
||||||
readonly isNamespaced: boolean;
|
readonly isNamespaced: boolean;
|
||||||
|
|
||||||
@ -264,23 +291,18 @@ export class KubeApi<T extends KubeObject> {
|
|||||||
private watchId = 1;
|
private watchId = 1;
|
||||||
|
|
||||||
constructor(protected options: IKubeApiOptions<T>) {
|
constructor(protected options: IKubeApiOptions<T>) {
|
||||||
const {
|
const { objectConstructor, request, kind, isNamespaced } = options;
|
||||||
objectConstructor,
|
|
||||||
request = apiKube,
|
|
||||||
kind = options.objectConstructor?.kind,
|
|
||||||
isNamespaced = options.objectConstructor?.namespaced,
|
|
||||||
} = options || {};
|
|
||||||
|
|
||||||
const { apiBase, apiPrefix, apiGroup, apiVersion, resource } = parseKubeApi(options.apiBase || objectConstructor.apiBase);
|
const { apiBase, apiPrefix, apiGroup, apiVersion, resource } = parseKubeApi(options.apiBase || objectConstructor.apiBase);
|
||||||
|
|
||||||
this.kind = kind;
|
this.options = options;
|
||||||
this.isNamespaced = isNamespaced;
|
this.kind = kind ?? objectConstructor.kind;
|
||||||
|
this.isNamespaced = isNamespaced ?? objectConstructor.namespaced ?? false;
|
||||||
this.apiBase = apiBase;
|
this.apiBase = apiBase;
|
||||||
this.apiPrefix = apiPrefix;
|
this.apiPrefix = apiPrefix;
|
||||||
this.apiGroup = apiGroup;
|
this.apiGroup = apiGroup;
|
||||||
this.apiVersion = apiVersion;
|
this.apiVersion = apiVersion;
|
||||||
this.apiResource = resource;
|
this.apiResource = resource;
|
||||||
this.request = request;
|
this.request = request ?? apiKube;
|
||||||
this.objectConstructor = objectConstructor;
|
this.objectConstructor = objectConstructor;
|
||||||
|
|
||||||
this.parseResponse = this.parseResponse.bind(this);
|
this.parseResponse = this.parseResponse.bind(this);
|
||||||
@ -353,21 +375,16 @@ export class KubeApi<T extends KubeObject> {
|
|||||||
const { apiPrefix, apiGroup } = await this.getPreferredVersionPrefixGroup();
|
const { apiPrefix, apiGroup } = await this.getPreferredVersionPrefixGroup();
|
||||||
|
|
||||||
// The apiPrefix and apiGroup might change due to fallbackApiBases, so we must override them
|
// The apiPrefix and apiGroup might change due to fallbackApiBases, so we must override them
|
||||||
Object.defineProperty(this, "apiPrefix", {
|
this.apiPrefix = apiPrefix;
|
||||||
value: apiPrefix,
|
this.apiGroup = apiGroup;
|
||||||
});
|
|
||||||
Object.defineProperty(this, "apiGroup", {
|
|
||||||
value: apiGroup,
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await this.request.get<IKubePreferredVersion>(`${this.apiPrefix}/${this.apiGroup}`);
|
const url = [apiPrefix, apiGroup].filter(Boolean).join("/");
|
||||||
|
const res = await this.request.get<IKubePreferredVersion>(url);
|
||||||
|
|
||||||
Object.defineProperty(this, "apiVersionPreferred", {
|
this.apiVersionPreferred = res?.preferredVersion?.version ?? null;
|
||||||
value: res?.preferredVersion?.version ?? null,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.apiVersionPreferred) {
|
if (this.apiVersionPreferred) {
|
||||||
Object.defineProperty(this, "apiBase", { value: this.getUrl() });
|
this.apiBase = this.computeApiBase();
|
||||||
apiManager.registerApi(this.apiBase, this);
|
apiManager.registerApi(this.apiBase, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,7 +402,15 @@ export class KubeApi<T extends KubeObject> {
|
|||||||
return this.list(params, { limit: 1 });
|
return this.list(params, { limit: 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
getUrl({ name, namespace = "default" }: Partial<ResourceDescriptor> = {}, query?: Partial<IKubeApiQueryParams>) {
|
private computeApiBase(): string {
|
||||||
|
return createKubeApiURL({
|
||||||
|
apiPrefix: this.apiPrefix,
|
||||||
|
apiVersion: this.apiVersionWithGroup,
|
||||||
|
resource: this.apiResource,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getUrl({ name, namespace }: Partial<ResourceDescriptor> = {}, query?: Partial<IKubeApiQueryParams>) {
|
||||||
const resourcePath = createKubeApiURL({
|
const resourcePath = createKubeApiURL({
|
||||||
apiPrefix: this.apiPrefix,
|
apiPrefix: this.apiPrefix,
|
||||||
apiVersion: this.apiVersionWithGroup,
|
apiVersion: this.apiVersionWithGroup,
|
||||||
|
|||||||
@ -90,15 +90,23 @@ if (process.env.LENS_DISABLE_GPU) {
|
|||||||
app.disableHardwareAcceleration();
|
app.disableHardwareAcceleration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("[APP-MAIN] initializing remote");
|
||||||
initializeRemote();
|
initializeRemote();
|
||||||
|
|
||||||
|
logger.debug("[APP-MAIN] configuring packages");
|
||||||
configurePackages();
|
configurePackages();
|
||||||
|
|
||||||
mangleProxyEnv();
|
mangleProxyEnv();
|
||||||
|
|
||||||
|
logger.debug("[APP-MAIN] initializing ipc main handlers");
|
||||||
initializers.initIpcMainHandlers();
|
initializers.initIpcMainHandlers();
|
||||||
|
|
||||||
if (app.commandLine.getSwitchValue("proxy-server") !== "") {
|
if (app.commandLine.getSwitchValue("proxy-server") !== "") {
|
||||||
process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server");
|
process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("[APP-MAIN] Lens protocol routing main");
|
||||||
|
|
||||||
if (!app.requestSingleInstanceLock()) {
|
if (!app.requestSingleInstanceLock()) {
|
||||||
app.exit();
|
app.exit();
|
||||||
} else {
|
} else {
|
||||||
@ -112,6 +120,8 @@ if (!app.requestSingleInstanceLock()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.on("second-instance", (event, argv) => {
|
app.on("second-instance", (event, argv) => {
|
||||||
|
logger.debug("second-instance message");
|
||||||
|
|
||||||
const lprm = LensProtocolRouterMain.createInstance();
|
const lprm = LensProtocolRouterMain.createInstance();
|
||||||
|
|
||||||
for (const arg of argv) {
|
for (const arg of argv) {
|
||||||
@ -295,6 +305,8 @@ autoUpdater.on("before-quit-for-update", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.on("will-quit", (event) => {
|
app.on("will-quit", (event) => {
|
||||||
|
logger.debug("will-quit message");
|
||||||
|
|
||||||
// This is called when the close button of the main window is clicked
|
// This is called when the close button of the main window is clicked
|
||||||
|
|
||||||
const lprm = LensProtocolRouterMain.getInstance(false);
|
const lprm = LensProtocolRouterMain.getInstance(false);
|
||||||
@ -324,6 +336,8 @@ app.on("will-quit", (event) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.on("open-url", (event, rawUrl) => {
|
app.on("open-url", (event, rawUrl) => {
|
||||||
|
logger.debug("open-url message");
|
||||||
|
|
||||||
// lens:// protocol handler
|
// lens:// protocol handler
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
LensProtocolRouterMain.getInstance().route(rawUrl);
|
LensProtocolRouterMain.getInstance().route(rawUrl);
|
||||||
@ -343,3 +357,5 @@ export {
|
|||||||
Mobx,
|
Mobx,
|
||||||
LensExtensions,
|
LensExtensions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
logger.debug("[APP-MAIN] waiting for 'ready' and other messages");
|
||||||
|
|||||||
@ -158,6 +158,8 @@ export abstract class ShellSession {
|
|||||||
cwd,
|
cwd,
|
||||||
env,
|
env,
|
||||||
name: "xterm-256color",
|
name: "xterm-256color",
|
||||||
|
// TODO: Something else is broken here so we need to force the use of winPty on windows
|
||||||
|
useConpty: false,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,6 @@ import { ClusterPageRegistry, getExtensionPageUrl } from "../extensions/registri
|
|||||||
import { ExtensionLoader } from "../extensions/extension-loader";
|
import { ExtensionLoader } from "../extensions/extension-loader";
|
||||||
import { appEventBus } from "../common/event-bus";
|
import { appEventBus } from "../common/event-bus";
|
||||||
import { requestMain } from "../common/ipc";
|
import { requestMain } from "../common/ipc";
|
||||||
import whatInput from "what-input";
|
|
||||||
import { clusterSetFrameIdHandler } from "../common/cluster-ipc";
|
import { clusterSetFrameIdHandler } from "../common/cluster-ipc";
|
||||||
import { ClusterPageMenuRegistration, ClusterPageMenuRegistry } from "../extensions/registries";
|
import { ClusterPageMenuRegistration, ClusterPageMenuRegistry } from "../extensions/registries";
|
||||||
import { StatefulSetScaleDialog } from "./components/+workloads-statefulsets/statefulset-scale-dialog";
|
import { StatefulSetScaleDialog } from "./components/+workloads-statefulsets/statefulset-scale-dialog";
|
||||||
@ -122,8 +121,6 @@ export class ClusterFrame extends React.Component {
|
|||||||
unmountComponentAtNode(rootElem);
|
unmountComponentAtNode(rootElem);
|
||||||
};
|
};
|
||||||
|
|
||||||
whatInput.ask(); // Start to monitor user input device
|
|
||||||
|
|
||||||
const clusterContext = new FrameContext(cluster);
|
const clusterContext = new FrameContext(cluster);
|
||||||
|
|
||||||
// Setup hosted cluster context
|
// Setup hosted cluster context
|
||||||
|
|||||||
@ -57,9 +57,7 @@ export class CrdResources extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@computed get store() {
|
@computed get store() {
|
||||||
if (!this.crd) return null;
|
return apiManager.getStore(this.crd?.getResourceApiBase());
|
||||||
|
|
||||||
return apiManager.getStore(this.crd.getResourceApiBase());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@ -29,15 +29,14 @@ import { CRDResourceStore } from "./crd-resource.store";
|
|||||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||||
|
|
||||||
function initStore(crd: CustomResourceDefinition) {
|
function initStore(crd: CustomResourceDefinition) {
|
||||||
const apiBase = crd.getResourceApiBase();
|
const objectConstructor = class extends KubeObject {
|
||||||
const kind = crd.getResourceKind();
|
static readonly kind = crd.getResourceKind();
|
||||||
const isNamespaced = crd.isNamespaced();
|
static readonly namespaced = crd.isNamespaced();
|
||||||
const api = apiManager.getApi(apiBase) ?? new KubeApi({
|
static readonly apiBase = crd.getResourceApiBase();
|
||||||
objectConstructor: KubeObject,
|
};
|
||||||
apiBase,
|
|
||||||
kind,
|
const api = apiManager.getApi(objectConstructor.apiBase)
|
||||||
isNamespaced,
|
?? new KubeApi({ objectConstructor });
|
||||||
});
|
|
||||||
|
|
||||||
if (!apiManager.getStore(api)) {
|
if (!apiManager.getStore(api)) {
|
||||||
apiManager.registerStore(new CRDResourceStore(api));
|
apiManager.registerStore(new CRDResourceStore(api));
|
||||||
|
|||||||
@ -153,7 +153,7 @@ export class ClusterStatus extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<div className={cssNames(styles.status, "flex column box center align-center justify-center", this.props.className)}>
|
<div className={cssNames(styles.status, "flex column box center align-center justify-center", this.props.className)}>
|
||||||
<div className="flex items-center column gaps">
|
<div className="flex items-center column gaps">
|
||||||
<h2>{this.entity.getName()}</h2>
|
<h2>{this.entity?.getName() ?? this.cluster.name}</h2>
|
||||||
{this.renderStatusIcon()}
|
{this.renderStatusIcon()}
|
||||||
{this.renderAuthenticationOutput()}
|
{this.renderAuthenticationOutput()}
|
||||||
{this.renderReconnectionHelp()}
|
{this.renderReconnectionHelp()}
|
||||||
|
|||||||
@ -127,7 +127,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--color-active);
|
color: var(--textColorAccent);
|
||||||
box-shadow: 0 0 0 2px var(--iconActiveBackground);
|
box-shadow: 0 0 0 2px var(--iconActiveBackground);
|
||||||
background-color: var(--iconActiveBackground);
|
background-color: var(--iconActiveBackground);
|
||||||
}
|
}
|
||||||
@ -137,16 +137,8 @@
|
|||||||
transition: 250ms color, 250ms opacity, 150ms background-color, 150ms box-shadow;
|
transition: 250ms color, 250ms opacity, 150ms background-color, 150ms box-shadow;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
|
|
||||||
&.focusable:focus:not(:hover) {
|
&.focusable:focus-visible {
|
||||||
box-shadow: 0 0 0 2px var(--focus-color);
|
box-shadow: 0 0 0 2px var(--focus-color);
|
||||||
|
|
||||||
[data-whatintent='mouse'] & {
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
box-shadow: 0 0 0 2px var(--iconActiveBackground);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|||||||
@ -32,7 +32,6 @@
|
|||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
.dropdown {
|
.dropdown {
|
||||||
box-shadow: 0 0 0 2px var(--focus-color);
|
box-shadow: 0 0 0 2px var(--focus-color);
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -61,11 +61,11 @@ export function initCatalogCategoryRegistryEntries() {
|
|||||||
ctx.menuItems.push(
|
ctx.menuItems.push(
|
||||||
{
|
{
|
||||||
icon: "create_new_folder",
|
icon: "create_new_folder",
|
||||||
title: "Sync kubeconfig folders(s)",
|
title: "Sync kubeconfig folder(s)",
|
||||||
defaultAction: true,
|
defaultAction: true,
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
await PathPicker.pick({
|
await PathPicker.pick({
|
||||||
label: "Sync folders(s)",
|
label: "Sync folder(s)",
|
||||||
buttonLabel: "Sync",
|
buttonLabel: "Sync",
|
||||||
properties: ["showHiddenFiles", "multiSelections", "openDirectory"],
|
properties: ["showHiddenFiles", "multiSelections", "openDirectory"],
|
||||||
onPick: addSyncEntries,
|
onPick: addSyncEntries,
|
||||||
|
|||||||
@ -14370,11 +14370,6 @@ websocket-extensions@>=0.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
|
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
|
||||||
integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
|
integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
|
||||||
|
|
||||||
what-input@^5.2.10:
|
|
||||||
version "5.2.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/what-input/-/what-input-5.2.10.tgz#f79f5b65cf95d75e55e6d580bb0a6b98174cad4e"
|
|
||||||
integrity sha512-7AQoIMGq7uU8esmKniOtZG3A+pzlwgeyFpkS3f/yzRbxknSL68tvn5gjE6bZ4OMFxCPjpaBd2udUTqlZ0HwrXQ==
|
|
||||||
|
|
||||||
whatwg-encoding@^1.0.5:
|
whatwg-encoding@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user