From ebbc1abb85d6437d96a211b0ecf6a717800df880 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Tue, 22 Dec 2020 14:52:35 +0300 Subject: [PATCH] Passing raw logs to PodLogs child components Signed-off-by: Alex Andreev --- .../components/dock/pod-log-controls.tsx | 13 +++--- src/renderer/components/dock/pod-log-list.tsx | 40 +++++++++++------ .../components/dock/pod-log-search.tsx | 5 ++- .../components/dock/pod-logs.store.ts | 44 ++++++++++++++----- src/renderer/components/dock/pod-logs.tsx | 26 +++-------- 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/src/renderer/components/dock/pod-log-controls.tsx b/src/renderer/components/dock/pod-log-controls.tsx index 1d91a9ca11..9c1212597d 100644 --- a/src/renderer/components/dock/pod-log-controls.tsx +++ b/src/renderer/components/dock/pod-log-controls.tsx @@ -22,10 +22,9 @@ interface Props extends PodLogSearchProps { } export const PodLogControls = observer((props: Props) => { - const { tabData, save, reload, tabId, logs } = props; + const { tabData, save, reload, logs } = props; const { selectedContainer, showTimestamps, previous } = tabData; - const rawLogs = podLogsStore.logs.get(tabId) || []; - const since = rawLogs.length ? podLogsStore.getTimestamps(rawLogs[0]) : null; + const since = logs.length ? podLogsStore.getTimestamps(logs[0]) : null; const pod = new Pod(tabData.pod); const toggleTimestamps = () => { @@ -39,8 +38,9 @@ export const PodLogControls = observer((props: Props) => { const downloadLogs = () => { const fileName = selectedContainer ? selectedContainer.name : pod.getName(); + const logsToDownload = showTimestamps ? logs : podLogsStore.logsWithoutTimestamps; - saveFileDialog(`${fileName}.log`, logs.join("\n"), "text/plain"); + saveFileDialog(`${fileName}.log`, logsToDownload.join("\n"), "text/plain"); }; const onContainerChange = (option: SelectOption) => { @@ -118,7 +118,10 @@ export const PodLogControls = observer((props: Props) => { tooltip={_i18n._(t`Save`)} className="download-icon" /> - + ); diff --git a/src/renderer/components/dock/pod-log-list.tsx b/src/renderer/components/dock/pod-log-list.tsx index a3ab172a16..60bd1a1050 100644 --- a/src/renderer/components/dock/pod-log-list.tsx +++ b/src/renderer/components/dock/pod-log-list.tsx @@ -5,7 +5,7 @@ import AnsiUp from "ansi_up"; import DOMPurify from "dompurify"; import debounce from "lodash/debounce"; import { Trans } from "@lingui/macro"; -import { action, observable } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Align, ListOnScrollProps } from "react-window"; @@ -15,7 +15,7 @@ import { Button } from "../button"; import { Icon } from "../icon"; import { Spinner } from "../spinner"; import { VirtualList } from "../virtual-list"; -import { logRange } from "./pod-logs.store"; +import { podLogsStore } from "./pod-logs.store"; interface Props { logs: string[] @@ -50,7 +50,6 @@ export class PodLogList extends React.Component { if (logs == prevProps.logs || !this.virtualListDiv.current) return; const newLogsLoaded = prevProps.logs.length < logs.length; const scrolledToBeginning = this.virtualListDiv.current.scrollTop === 0; - const fewLogsLoaded = logs.length < logRange; if (this.isLastLineVisible) { this.scrollToBottom(); // Scroll down to keep user watching/reading experience @@ -59,11 +58,12 @@ export class PodLogList extends React.Component { } if (scrolledToBeginning && newLogsLoaded) { - this.virtualListDiv.current.scrollTop = (logs.length - prevProps.logs.length) * this.lineHeight; - } + const firstLineContents = prevProps.logs[0]; + const lineToScroll = this.props.logs.findIndex((value) => value == firstLineContents); - if (fewLogsLoaded) { - this.isJumpButtonVisible = false; + if (lineToScroll !== -1) { + this.scrollToItem(lineToScroll, "start"); + } } if (!logs.length) { @@ -71,6 +71,20 @@ export class PodLogList extends React.Component { } } + /** + * Returns logs with or without timestamps regarding to showTimestamps prop + */ + @computed + get logs() { + const showTimestamps = podLogsStore.getData(this.props.id).showTimestamps; + + if (!showTimestamps) { + return podLogsStore.logsWithoutTimestamps; + } + + return this.props.logs; + } + /** * Checks if JumpToBottom button should be visible and sets its observable * @param props Scrolling props from virtual list core @@ -137,7 +151,7 @@ export class PodLogList extends React.Component { */ getLogRow = (rowIndex: number) => { const { searchQuery, isActiveOverlay } = searchStore; - const item = this.props.logs[rowIndex]; + const item = this.logs[rowIndex]; const contents: React.ReactElement[] = []; const ansiToHtml = (ansi: string) => DOMPurify.sanitize(colorConverter.ansi_to_html(ansi)); @@ -179,15 +193,15 @@ export class PodLogList extends React.Component { }; render() { - const { logs, isLoading } = this.props; - const isInitLoading = isLoading && !logs.length; - const rowHeights = new Array(logs.length).fill(this.lineHeight); + const { isLoading } = this.props; + const isInitLoading = isLoading && !this.logs.length; + const rowHeights = new Array(this.logs.length).fill(this.lineHeight); if (isInitLoading) { return ; } - if (!logs.length) { + if (!this.logs.length) { return (
There are no logs available for container @@ -198,7 +212,7 @@ export class PodLogList extends React.Component { return (
void toPrevOverlay: () => void toNextOverlay: () => void +} + +interface Props extends PodLogSearchProps { logs: string[] } -export const PodLogSearch = observer((props: PodLogSearchProps) => { +export const PodLogSearch = observer((props: Props) => { const { logs, onSearch, toPrevOverlay, toNextOverlay } = props; const { setNextOverlayActive, setPrevOverlayActive, searchQuery, occurrences, activeFind, totalFinds } = searchStore; const jumpDisabled = !searchQuery || !occurrences.length; diff --git a/src/renderer/components/dock/pod-logs.store.ts b/src/renderer/components/dock/pod-logs.store.ts index 057b8eea15..2f3574d115 100644 --- a/src/renderer/components/dock/pod-logs.store.ts +++ b/src/renderer/components/dock/pod-logs.store.ts @@ -27,11 +27,11 @@ export class PodLogsStore extends DockTabStore { private refresher = interval(10, () => { const id = dockStore.selectedTabId; - if (!this.logs.get(id)) return; + if (!this.podLogs.get(id)) return; this.loadMore(id); }); - @observable logs = observable.map(); + @observable podLogs = observable.map(); @observable newLogSince = observable.map(); // Timestamp after which all logs are considered to be new constructor() { @@ -48,7 +48,7 @@ export class PodLogsStore extends DockTabStore { } }, { delay: 500 }); - reaction(() => this.logs.get(dockStore.selectedTabId), () => { + reaction(() => this.podLogs.get(dockStore.selectedTabId), () => { this.setNewLogSince(dockStore.selectedTabId); }); @@ -72,7 +72,7 @@ export class PodLogsStore extends DockTabStore { }); this.refresher.start(); - this.logs.set(tabId, logs); + this.podLogs.set(tabId, logs); } catch ({error}) { const message = [ _i18n._(t`Failed to load logs: ${error.message}`), @@ -80,7 +80,7 @@ export class PodLogsStore extends DockTabStore { ]; this.refresher.stop(); - this.logs.set(tabId, message); + this.podLogs.set(tabId, message); } }; @@ -91,14 +91,14 @@ export class PodLogsStore extends DockTabStore { * @param tabId */ loadMore = async (tabId: TabId) => { - if (!this.logs.get(tabId).length) return; - const oldLogs = this.logs.get(tabId); + if (!this.podLogs.get(tabId).length) return; + const oldLogs = this.podLogs.get(tabId); const logs = await this.loadLogs(tabId, { sinceTime: this.getLastSinceTime(tabId) }); // Add newly received logs to bottom - this.logs.set(tabId, [...oldLogs, ...logs]); + this.podLogs.set(tabId, [...oldLogs, ...logs]); }; /** @@ -134,7 +134,7 @@ export class PodLogsStore extends DockTabStore { * @param tabId */ setNewLogSince(tabId: TabId) { - if (!this.logs.has(tabId) || !this.logs.get(tabId).length || this.newLogSince.has(tabId)) return; + if (!this.podLogs.has(tabId) || !this.podLogs.get(tabId).length || this.newLogSince.has(tabId)) return; const timestamp = this.getLastSinceTime(tabId); this.newLogSince.set(tabId, timestamp.split(".")[0]); // Removing milliseconds from string @@ -147,18 +147,38 @@ export class PodLogsStore extends DockTabStore { @computed get lines() { const id = dockStore.selectedTabId; - const logs = this.logs.get(id); + const logs = this.podLogs.get(id); return logs ? logs.length : 0; } + + /** + * Returns logs with timestamps for selected tab + */ + get logs() { + const id = dockStore.selectedTabId; + + if (!this.podLogs.has(id)) return []; + + return this.podLogs.get(id); + } + + /** + * Removes timestamps from each log line and returns changed logs + * @returns Logs without timestamps + */ + get logsWithoutTimestamps() { + return this.logs.map(item => this.removeTimestamps(item)); + } + /** * It gets timestamps from all logs then returns last one + 1 second * (this allows to avoid getting the last stamp in the selection) * @param tabId */ getLastSinceTime(tabId: TabId) { - const logs = this.logs.get(tabId); + const logs = this.podLogs.get(tabId); const timestamps = this.getTimestamps(logs[logs.length - 1]); const stamp = new Date(timestamps ? timestamps[0] : null); @@ -176,7 +196,7 @@ export class PodLogsStore extends DockTabStore { } clearLogs(tabId: TabId) { - this.logs.delete(tabId); + this.podLogs.delete(tabId); } clearData(tabId: TabId) { diff --git a/src/renderer/components/dock/pod-logs.tsx b/src/renderer/components/dock/pod-logs.tsx index 5b9c2860c4..fd4002141b 100644 --- a/src/renderer/components/dock/pod-logs.tsx +++ b/src/renderer/components/dock/pod-logs.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { computed, observable, reaction } from "mobx"; +import { observable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { searchStore } from "../../../common/search-store"; @@ -79,31 +79,15 @@ export class PodLogs extends React.Component { }, 100); } - /** - * Computed prop which returns logs with or without timestamps added to each line - * @returns {Array} An array log items - */ - @computed - get logs(): string[] { - if (!podLogsStore.logs.has(this.tabId)) return []; - const logs = podLogsStore.logs.get(this.tabId); - const { getData, removeTimestamps } = podLogsStore; - const { showTimestamps } = getData(this.tabId); - - if (!showTimestamps) { - return logs.map(item => removeTimestamps(item)); - } - - return logs; - } - render() { + const logs = podLogsStore.logs; + const controls = ( { showButtons={false} />