mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Improve Table typing and remove annotations on callbacks (#2981)
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
c6a4d55d86
commit
64ac04186b
59 files changed
+487
-482
No files matched your search
@@ -22,8 +22,9 @@
|
||||
import { ingressStore } from "../../components/+network-ingresses/ingress.store";
|
||||
import { apiManager } from "../api-manager";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
class TestApi extends KubeApi {
|
||||
class TestApi extends KubeApi<KubeObject> {
|
||||
|
||||
protected async checkPreferredVersion() {
|
||||
return;
|
||||
@@ -36,6 +37,7 @@ describe("ApiManager", () => {
|
||||
const apiBase = "apis/v1/foo";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/foo";
|
||||
const kubeApi = new TestApi({
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
checkPreferredVersion: true,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import { CustomResourceDefinition } from "../endpoints";
|
||||
import type { IKubeObjectMetadata } from "../kube-object";
|
||||
import type { KubeObjectMetadata } from "../kube-object";
|
||||
|
||||
describe("Crds", () => {
|
||||
describe("getVersion", () => {
|
||||
@@ -28,7 +28,7 @@ describe("Crds", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as IKubeObjectMetadata,
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
@@ -48,7 +48,7 @@ describe("Crds", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as IKubeObjectMetadata,
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
@@ -73,7 +73,7 @@ describe("Crds", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as IKubeObjectMetadata,
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
@@ -99,7 +99,7 @@ describe("Crds", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as IKubeObjectMetadata,
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
describe("KubeApi", () => {
|
||||
it("uses url from apiBase if apiBase contains the resource", async () => {
|
||||
@@ -29,7 +30,7 @@ describe("KubeApi", () => {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses"
|
||||
}] as any []
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else if (request.url === "/api-kube/apis/extensions/v1beta1") {
|
||||
@@ -38,13 +39,13 @@ describe("KubeApi", () => {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses"
|
||||
}] as any []
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any []
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
}
|
||||
@@ -53,6 +54,7 @@ describe("KubeApi", () => {
|
||||
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new KubeApi({
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
checkPreferredVersion: true,
|
||||
@@ -68,7 +70,7 @@ describe("KubeApi", () => {
|
||||
if (request.url === "/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any []
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
} else if (request.url === "/api-kube/apis/extensions/v1beta1") {
|
||||
@@ -76,13 +78,13 @@ describe("KubeApi", () => {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses"
|
||||
}] as any []
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any []
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
}
|
||||
@@ -91,6 +93,7 @@ describe("KubeApi", () => {
|
||||
const apiBase = "apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new KubeApi({
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
checkPreferredVersion: true,
|
||||
|
||||
@@ -22,34 +22,35 @@
|
||||
import type { KubeObjectStore } from "../kube-object.store";
|
||||
|
||||
import { action, observable, makeObservable } from "mobx";
|
||||
import { autoBind } from "../utils";
|
||||
import { autoBind, iter } from "../utils";
|
||||
import { KubeApi, parseKubeApi } from "./kube-api";
|
||||
import type { KubeObject } from "./kube-object";
|
||||
|
||||
export class ApiManager {
|
||||
private apis = observable.map<string, KubeApi>();
|
||||
private stores = observable.map<string, KubeObjectStore>();
|
||||
private apis = observable.map<string, KubeApi<KubeObject>>();
|
||||
private stores = observable.map<string, KubeObjectStore<KubeObject>>();
|
||||
|
||||
constructor() {
|
||||
makeObservable(this);
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) {
|
||||
getApi(pathOrCallback: string | ((api: KubeApi<KubeObject>) => boolean)) {
|
||||
if (typeof pathOrCallback === "string") {
|
||||
return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase);
|
||||
}
|
||||
|
||||
return Array.from(this.apis.values()).find(pathOrCallback ?? (() => true));
|
||||
return iter.find(this.apis.values(), pathOrCallback ?? (() => true));
|
||||
}
|
||||
|
||||
getApiByKind(kind: string, apiVersion: string) {
|
||||
return Array.from(this.apis.values()).find((api) => api.kind === kind && api.apiVersionWithGroup === apiVersion);
|
||||
return iter.find(this.apis.values(), api => api.kind === kind && api.apiVersionWithGroup === apiVersion);
|
||||
}
|
||||
|
||||
registerApi(apiBase: string, api: KubeApi) {
|
||||
registerApi(apiBase: string, api: KubeApi<KubeObject>) {
|
||||
if (!this.apis.has(apiBase)) {
|
||||
this.stores.forEach((store) => {
|
||||
if(store.api === api) {
|
||||
if (store.api === api) {
|
||||
this.stores.set(apiBase, store);
|
||||
}
|
||||
});
|
||||
@@ -58,19 +59,19 @@ export class ApiManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected resolveApi(api?: string | KubeApi): KubeApi | undefined {
|
||||
protected resolveApi<K extends KubeObject>(api?: string | KubeApi<K>): KubeApi<K> | undefined {
|
||||
if (!api) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof api === "string") {
|
||||
return this.getApi(api);
|
||||
return this.getApi(api) as KubeApi<K>;
|
||||
}
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
unregisterApi(api: string | KubeApi) {
|
||||
unregisterApi(api: string | KubeApi<KubeObject>) {
|
||||
if (typeof api === "string") this.apis.delete(api);
|
||||
else {
|
||||
const apis = Array.from(this.apis.entries());
|
||||
@@ -81,13 +82,13 @@ export class ApiManager {
|
||||
}
|
||||
|
||||
@action
|
||||
registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) {
|
||||
registerStore(store: KubeObjectStore<KubeObject>, apis: KubeApi<KubeObject>[] = [store.api]) {
|
||||
apis.forEach(api => {
|
||||
this.stores.set(api.apiBase, store);
|
||||
});
|
||||
}
|
||||
|
||||
getStore<S extends KubeObjectStore>(api: string | KubeApi): S {
|
||||
getStore<S extends KubeObjectStore<KubeObject>>(api: string | KubeApi<KubeObject>): S | undefined {
|
||||
return this.stores.get(this.resolveApi(api)?.apiBase) as S;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export const resourceApplierApi = {
|
||||
"kubectl.kubernetes.io/last-applied-configuration"
|
||||
],
|
||||
|
||||
async update<D extends KubeObject>(resource: object | string): Promise<D> {
|
||||
async update<K extends KubeObject>(resource: object | string): Promise<K | null> {
|
||||
if (typeof resource === "string") {
|
||||
resource = jsYaml.safeLoad(resource);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ export const resourceApplierApi = {
|
||||
}
|
||||
});
|
||||
|
||||
return items.length === 1 ? items[0] : items;
|
||||
return items[0] as K ?? null;
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -28,7 +28,7 @@ import logger from "../../main/logger";
|
||||
import { apiManager } from "./api-manager";
|
||||
import { apiKube } from "./index";
|
||||
import { createKubeApiURL, parseKubeApi } from "./kube-api-parse";
|
||||
import { IKubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object";
|
||||
import { KubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object";
|
||||
import byline from "byline";
|
||||
import type { IKubeWatchEvent } from "./kube-watch-api";
|
||||
import { ReadableWebToNodeStream } from "../utils/readableStream";
|
||||
@@ -49,7 +49,7 @@ export interface IKubeApiOptions<T extends KubeObject> {
|
||||
*/
|
||||
fallbackApiBases?: string[];
|
||||
|
||||
objectConstructor?: IKubeObjectConstructor<T>;
|
||||
objectConstructor: KubeObjectConstructor<T>;
|
||||
request?: KubeJsonApi;
|
||||
isNamespaced?: boolean;
|
||||
kind?: string;
|
||||
@@ -99,7 +99,7 @@ export interface IKubeApiCluster {
|
||||
}
|
||||
}
|
||||
|
||||
export function forCluster<T extends KubeObject>(cluster: IKubeApiCluster, kubeClass: IKubeObjectConstructor<T>): KubeApi<T> {
|
||||
export function forCluster<T extends KubeObject>(cluster: IKubeApiCluster, kubeClass: KubeObjectConstructor<T>): KubeApi<T> {
|
||||
const request = new KubeJsonApi({
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
@@ -115,7 +115,7 @@ export function forCluster<T extends KubeObject>(cluster: IKubeApiCluster, kubeC
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureObjectSelfLink(api: KubeApi, object: KubeJsonApiData) {
|
||||
export function ensureObjectSelfLink(api: KubeApi<KubeObject>, object: KubeJsonApiData) {
|
||||
if (!object.metadata.selfLink) {
|
||||
object.metadata.selfLink = createKubeApiURL({
|
||||
apiPrefix: api.apiPrefix,
|
||||
@@ -127,7 +127,7 @@ export function ensureObjectSelfLink(api: KubeApi, object: KubeJsonApiData) {
|
||||
}
|
||||
}
|
||||
|
||||
export type KubeApiWatchCallback = (data: IKubeWatchEvent, error: any) => void;
|
||||
export type KubeApiWatchCallback = (data: IKubeWatchEvent<KubeJsonApiData>, error: any) => void;
|
||||
|
||||
export type KubeApiWatchOptions = {
|
||||
namespace: string;
|
||||
@@ -135,7 +135,7 @@ export type KubeApiWatchOptions = {
|
||||
abortController?: AbortController
|
||||
};
|
||||
|
||||
export class KubeApi<T extends KubeObject = any> {
|
||||
export class KubeApi<T extends KubeObject> {
|
||||
readonly kind: string;
|
||||
readonly apiBase: string;
|
||||
readonly apiPrefix: string;
|
||||
@@ -145,14 +145,14 @@ export class KubeApi<T extends KubeObject = any> {
|
||||
readonly apiResource: string;
|
||||
readonly isNamespaced: boolean;
|
||||
|
||||
public objectConstructor: IKubeObjectConstructor<T>;
|
||||
public objectConstructor: KubeObjectConstructor<T>;
|
||||
protected request: KubeJsonApi;
|
||||
protected resourceVersions = new Map<string, string>();
|
||||
protected watchDisposer: () => void;
|
||||
|
||||
constructor(protected options: IKubeApiOptions<T>) {
|
||||
const {
|
||||
objectConstructor = KubeObject as IKubeObjectConstructor,
|
||||
objectConstructor,
|
||||
request = apiKube,
|
||||
kind = options.objectConstructor?.kind,
|
||||
isNamespaced = options.objectConstructor?.namespaced
|
||||
@@ -456,14 +456,14 @@ export class KubeApi<T extends KubeObject = any> {
|
||||
|
||||
clearTimeout(timedRetry);
|
||||
timedRetry = setTimeout(() => { // we did not get any kubernetes errors so let's retry
|
||||
this.watch({...opts, namespace, callback});
|
||||
this.watch({ ...opts, namespace, callback });
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
byline(nodeStream).on("data", (line) => {
|
||||
try {
|
||||
const event: IKubeWatchEvent = JSON.parse(line);
|
||||
const event: IKubeWatchEvent<KubeJsonApiData> = JSON.parse(line);
|
||||
|
||||
if (event.type === "ERROR" && event.object.kind === "Status") {
|
||||
errorReceived = true;
|
||||
@@ -474,7 +474,7 @@ export class KubeApi<T extends KubeObject = any> {
|
||||
this.modifyWatchEvent(event);
|
||||
callback(event, null);
|
||||
} catch (ignore) {
|
||||
// ignore parse errors
|
||||
// ignore parse errors
|
||||
}
|
||||
});
|
||||
})
|
||||
@@ -487,7 +487,7 @@ export class KubeApi<T extends KubeObject = any> {
|
||||
return abort;
|
||||
}
|
||||
|
||||
protected modifyWatchEvent(event: IKubeWatchEvent) {
|
||||
protected modifyWatchEvent(event: IKubeWatchEvent<KubeJsonApiData>) {
|
||||
|
||||
switch (event.type) {
|
||||
case "ADDED":
|
||||
|
||||
@@ -31,13 +31,13 @@ import { resourceApplierApi } from "./endpoints/resource-applier.api";
|
||||
import { hasOptionalProperty, hasTypedProperty, isObject, isString, bindPredicate, isTypedArray, isRecord } from "../../common/utils/type-narrowing";
|
||||
import _ from "lodash";
|
||||
|
||||
export type IKubeObjectConstructor<T extends KubeObject = any> = (new (data: KubeJsonApiData | any) => T) & {
|
||||
export type KubeObjectConstructor<K extends KubeObject> = (new (data: KubeJsonApiData | any) => K) & {
|
||||
kind?: string;
|
||||
namespaced?: boolean;
|
||||
apiBase?: string;
|
||||
};
|
||||
|
||||
export interface IKubeObjectMetadata {
|
||||
export interface KubeObjectMetadata {
|
||||
uid: string;
|
||||
name: string;
|
||||
namespace?: string;
|
||||
@@ -63,7 +63,7 @@ export interface IKubeObjectMetadata {
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface IKubeStatus {
|
||||
export interface KubeStatusData {
|
||||
kind: string;
|
||||
apiVersion: string;
|
||||
code: number;
|
||||
@@ -78,7 +78,7 @@ export class KubeStatus {
|
||||
public readonly message: string;
|
||||
public readonly reason: string;
|
||||
|
||||
constructor(data: IKubeStatus) {
|
||||
constructor(data: KubeStatusData) {
|
||||
this.apiVersion = data.apiVersion;
|
||||
this.code = data.code;
|
||||
this.message = data.message || "";
|
||||
@@ -86,9 +86,9 @@ export class KubeStatus {
|
||||
}
|
||||
}
|
||||
|
||||
export type IKubeMetaField = keyof IKubeObjectMetadata;
|
||||
export type KubeMetaField = keyof KubeObjectMetadata;
|
||||
|
||||
export class KubeObject<Metadata extends IKubeObjectMetadata = IKubeObjectMetadata, Status = any, Spec = any> implements ItemObject {
|
||||
export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata, Status = any, Spec = any> implements ItemObject {
|
||||
static readonly kind: string;
|
||||
static readonly namespaced: boolean;
|
||||
|
||||
@@ -277,14 +277,14 @@ export class KubeObject<Metadata extends IKubeObjectMetadata = IKubeObjectMetada
|
||||
}
|
||||
|
||||
// use unified resource-applier api for updating all k8s objects
|
||||
async update<T extends KubeObject>(data: Partial<T>): Promise<T> {
|
||||
async update<K extends KubeObject>(data: Partial<K>): Promise<K> {
|
||||
for (const field of KubeObject.nonEditableFields) {
|
||||
if (!_.isEqual(_.get(this, field), _.get(data, field))) {
|
||||
throw new Error(`Failed to update Kube Object: ${field} has been modified`);
|
||||
}
|
||||
}
|
||||
|
||||
return resourceApplierApi.update<T>({
|
||||
return resourceApplierApi.update<K>({
|
||||
...this.toPlainObject(),
|
||||
...data,
|
||||
});
|
||||
|
||||
@@ -31,8 +31,9 @@ import { autoBind, Disposer, noop } from "../utils";
|
||||
import type { KubeApi } from "./kube-api";
|
||||
import type { KubeJsonApiData } from "./kube-json-api";
|
||||
import { isDebugging, isProduction } from "../../common/vars";
|
||||
import type { KubeObject } from "./kube-object";
|
||||
|
||||
export interface IKubeWatchEvent<T = KubeJsonApiData> {
|
||||
export interface IKubeWatchEvent<T extends KubeJsonApiData> {
|
||||
type: "ADDED" | "MODIFIED" | "DELETED" | "ERROR";
|
||||
object?: T;
|
||||
}
|
||||
@@ -58,11 +59,11 @@ export class KubeWatchApi {
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
isAllowedApi(api: KubeApi): boolean {
|
||||
isAllowedApi(api: KubeApi<KubeObject>): boolean {
|
||||
return Boolean(this.context?.cluster.isAllowedResource(api.kind));
|
||||
}
|
||||
|
||||
preloadStores(stores: KubeObjectStore[], opts: { namespaces?: string[], loadOnce?: boolean } = {}) {
|
||||
preloadStores(stores: KubeObjectStore<KubeObject>[], opts: { namespaces?: string[], loadOnce?: boolean } = {}) {
|
||||
const limitRequests = plimit(1); // load stores one by one to allow quick skipping when fast clicking btw pages
|
||||
const preloading: Promise<any>[] = [];
|
||||
|
||||
@@ -80,7 +81,7 @@ export class KubeWatchApi {
|
||||
};
|
||||
}
|
||||
|
||||
subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer {
|
||||
subscribeStores(stores: KubeObjectStore<KubeObject>[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer {
|
||||
const { preload = true, waitUntilLoaded = true, loadOnce = false, } = opts;
|
||||
const subscribingNamespaces = opts.namespaces ?? this.context?.allNamespaces ?? [];
|
||||
const unsubscribeList: Function[] = [];
|
||||
|
||||
Reference in new issue
Block a user