diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index d3b2b4512a..0fd2e207b5 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -37,8 +37,9 @@ export interface IKubeWatchReconnectOptions { } export interface IKubeWatchLog { - message: string | Error; + message: string | string[] | Error; meta?: object; + cssStyle?: string; } @autobind() @@ -250,7 +251,7 @@ export class KubeWatchApi { if (done) break; // exit - const events = (jsonBuffer + value).split("\n"); + const events = (jsonBuffer + value).trim().split("\n"); jsonBuffer = this.processBuffer(events); } @@ -273,12 +274,29 @@ export class KubeWatchApi { try { const kubeEvent: IKubeWatchEvent = JSON.parse(json); const message = this.getMessage(kubeEvent); + const { data, namespace } = message; - if (!this.namespaces.includes(message.namespace)) { - continue; // skip updates from non-watching resources context + if (!this.isAllowedApi(message.api)) { + return; } - this.onMessage.emit(message); + // log all data events + if (data) { + this.log({ + message: `[${data.type}] ${data.object.kind} in ${namespace || "(cluster)"}`, + meta: data, + cssStyle: `color: ${[ + data.type === "ADDED" && "green", + data.type === "MODIFIED" && "darkgray", + data.type === "DELETED" && "red", + ].filter(Boolean)};`, + }); + } + + // skip updates from non-watching resources context + if (!namespace || this.namespaces.includes(namespace)) { + this.onMessage.emit(message); + } } catch (error) { return json; } @@ -353,20 +371,21 @@ export class KubeWatchApi { } } - protected log({ message, meta = {} }: IKubeWatchLog) { + protected log({ message, cssStyle = "", meta = {} }: IKubeWatchLog) { if (isProduction && !isDebugging) { return; } - const logMessage = `%c[KUBE-WATCH-API]: ${String(message).toUpperCase()}`; - const isError = message instanceof Error; - const textStyle = `font-weight: bold;`; - const time = new Date().toLocaleString(); + const logInfo = [`%c[KUBE-WATCH-API]:`, `font-weight: bold; ${cssStyle}`, message].flat().map(String); + const logMeta = { + time: new Date().toLocaleString(), + ...meta, + }; - if (isError) { - console.error(logMessage, textStyle, { time, ...meta }); + if (message instanceof Error) { + console.error(...logInfo, logMeta); } else { - console.info(logMessage, textStyle, { time, ...meta }); + console.info(...logInfo, logMeta); } } } diff --git a/src/renderer/item.store.ts b/src/renderer/item.store.ts index eccd2b52df..40df2282fd 100644 --- a/src/renderer/item.store.ts +++ b/src/renderer/item.store.ts @@ -27,6 +27,10 @@ export abstract class ItemStore { return this.items.find(item => item.getName() === name); } + getIndex(item: T): number { + return this.items.findIndex(i => i === item); + } + @action protected sortItems(items: T[] = this.items, sorting?: ((item: T) => any)[], order?: "asc" | "desc"): T[] { return orderBy(items, sorting || this.defaultSorting, order); diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index d56e6bd912..9fe51d6ab4 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -204,12 +204,12 @@ export abstract class KubeObjectStore extends ItemSt protected eventsBuffer = observable.array>([], { deep: false }); protected bindWatchEventsUpdater(delay = 1000) { - kubeWatchApi.onMessage.addListener(({ store, data }: IKubeWatchMessage) => { - if (!this.isLoaded || store !== this) return; - this.eventsBuffer.push(data); + kubeWatchApi.onMessage.addListener((evt: IKubeWatchMessage) => { + if (!this.isLoaded || evt.store !== this) return; + this.eventsBuffer.push(evt.data); }); - reaction(() => this.eventsBuffer.length > 0, this.updateFromEventsBuffer, { + reaction(() => this.eventsBuffer.length, this.updateFromEventsBuffer, { delay }); } @@ -224,11 +224,14 @@ export abstract class KubeObjectStore extends ItemSt @action protected updateFromEventsBuffer() { - const items = this.items.toJS(); + const eventsBuffer = this.eventsBuffer.clear(); - for (const { type, object } of this.eventsBuffer.clear()) { - const index = items.findIndex(item => item.getId() === object.metadata?.uid); - const item = items[index]; + if (!eventsBuffer.length) { + return; + } + + for (const { type, object } of eventsBuffer) { + const item = this.getById(object.metadata?.uid); const api = apiManager.getApiByKind(object.kind, object.apiVersion); switch (type) { @@ -237,20 +240,22 @@ export abstract class KubeObjectStore extends ItemSt const newItem = new api.objectConstructor(object); if (!item) { - items.push(newItem); + this.items.push(newItem); } else { - items.splice(index, 1, newItem); + const index = this.getIndex(item); + + this.items.splice(index, 1, newItem); } break; case "DELETED": - if (item) { - items.splice(index, 1); - } + this.items.remove(item); break; } } - // update items - this.items.replace(this.sortItems(items.slice(-this.bufferSize))); + // sort and limit items to store's maximum + const newItems = this.sortItems(this.items.slice(-this.bufferSize)); + + this.items.replace(newItems); } }