From a1b38b2b0462763b6122908db6b24e5de17d1501 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Wed, 7 Oct 2020 13:40:19 +0300 Subject: [PATCH] Removing PodLogsDialog Signed-off-by: Alex Andreev --- .../+workloads-pods/pod-logs-dialog.scss | 110 ------- .../+workloads-pods/pod-logs-dialog.tsx | 307 ------------------ src/renderer/components/app.tsx | 1 - 3 files changed, 418 deletions(-) delete mode 100644 src/renderer/components/+workloads-pods/pod-logs-dialog.scss delete mode 100644 src/renderer/components/+workloads-pods/pod-logs-dialog.tsx diff --git a/src/renderer/components/+workloads-pods/pod-logs-dialog.scss b/src/renderer/components/+workloads-pods/pod-logs-dialog.scss deleted file mode 100644 index 0c8845c78f..0000000000 --- a/src/renderer/components/+workloads-pods/pod-logs-dialog.scss +++ /dev/null @@ -1,110 +0,0 @@ -.PodLogsDialog { - --log-line-height: 16px; - - .Wizard { - width: 90vw; - max-height: none; - - .WizardStep { - & > .step-content.scrollable { - max-height: none; - } - - & > :last-child { - padding: $padding * 2; - } - } - } - - .log-controls { - padding-bottom: $padding * 2; - - .time-range { - flex-grow: 2; - text-align: center; - } - - .controls { - width: 100%; - } - - .control-buttons { - margin-right: 0; - white-space: nowrap; - - .Icon { - border-radius: $radius; - padding: 3px; - - &:hover { - color: $textColorPrimary; - background: #f4f4f4; - } - - &.active { - color: $primary; - background: #f4f4f4; - } - } - } - - @include media("<=desktop") { - flex-direction: column; - align-items: start; - - .container { - width: 100%; - } - - .controls { - margin-top: $margin * 2; - - .time-range { - text-align: left; - } - } - } - } - - .logs-area { - position: relative; - @include custom-scrollbar; - - // fix for `this.logsArea.scrollTop = this.logsArea.scrollHeight` - // `overflow: overlay` don't allow scroll to the last line - overflow: auto; - - color: #C5C8C6; - background: #1D1F21; - line-height: var(--log-line-height); - border-radius: 2px; - height: 45vh; - padding: $padding / 4 $padding; - font-family: $font-monospace; - font-size: smaller; - white-space: pre; - - .no-logs { - text-align: center; - } - } - - .new-logs-sep { - position: relative; - display: block; - height: 0; - border-top: 1px solid $primary; - margin: $margin * 2; - - &:after { - position: absolute; - left: 50%; - transform: translate(-50%, -50%); - content: 'new'; - background: $primary; - color: white; - padding: $padding / 3 $padding /2; - border-radius: $radius; - } - } -} \ No newline at end of file diff --git a/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx b/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx deleted file mode 100644 index d7ff3863cc..0000000000 --- a/src/renderer/components/+workloads-pods/pod-logs-dialog.tsx +++ /dev/null @@ -1,307 +0,0 @@ -import "./pod-logs-dialog.scss"; - -import React from "react"; -import { observable } from "mobx"; -import { observer } from "mobx-react"; -import { t, Trans } from "@lingui/macro"; -import { _i18n } from "../../i18n"; -import { Dialog, DialogProps } from "../dialog"; -import { Wizard, WizardStep } from "../wizard"; -import { IPodContainer, Pod, podsApi } from "../../api/endpoints"; -import { Icon } from "../icon"; -import { Select, SelectOption } from "../select"; -import { Spinner } from "../spinner"; -import { cssNames, downloadFile, interval } from "../../utils"; -import AnsiUp from "ansi_up"; -import DOMPurify from "dompurify" - -interface IPodLogsDialogData { - pod: Pod; - container?: IPodContainer; -} - -interface Props extends Partial { -} - -@observer -export class PodLogsDialog extends React.Component { - @observable static isOpen = false; - @observable static data: IPodLogsDialogData = null; - - static open(pod: Pod, container?: IPodContainer) { - PodLogsDialog.isOpen = true; - PodLogsDialog.data = { pod, container }; - } - - static close() { - PodLogsDialog.isOpen = false; - } - - get data() { - return PodLogsDialog.data; - } - - private logsArea: HTMLDivElement; - private refresher = interval(5, () => this.load()); - private containers: IPodContainer[] = [] - private initContainers: IPodContainer[] = [] - private lastLineIsShown = true; // used for proper auto-scroll content after refresh - private colorConverter = new AnsiUp(); - - @observable logs = ""; // latest downloaded logs for pod - @observable newLogs = ""; // new logs since dialog is open - @observable logsReady = false; - @observable selectedContainer: IPodContainer; - @observable showTimestamps = true; - @observable tailLines = 1000; - - lineOptions = [ - { label: _i18n._(t`All logs`), value: Number.MAX_SAFE_INTEGER }, - { label: 1000, value: 1000 }, - { label: 10000, value: 10000 }, - { label: 100000, value: 100000 }, - ] - - onOpen = async () => { - const { pod, container } = this.data; - this.containers = pod.getContainers(); - this.initContainers = pod.getInitContainers(); - this.selectedContainer = container || this.containers[0]; - await this.load(); - this.refresher.start(); - } - - onClose = () => { - this.resetLogs(); - this.refresher.stop(); - } - - close = () => { - PodLogsDialog.close(); - } - - load = async () => { - if (!this.data) return; - const { pod } = this.data; - try { - // if logs already loaded, check the latest timestamp for getting updates only from this point - const logsTimestamps = this.getTimestamps(this.newLogs || this.logs); - let lastLogDate = new Date(0) - if (logsTimestamps) { - lastLogDate = new Date(logsTimestamps.slice(-1)[0]); - lastLogDate.setSeconds(lastLogDate.getSeconds() + 1); // avoid duplicates from last second - } - const namespace = pod.getNs(); - const name = pod.getName(); - const logs = await podsApi.getLogs({ namespace, name }, { - container: this.selectedContainer.name, - timestamps: true, - tailLines: this.tailLines ? this.tailLines : undefined, - sinceTime: lastLogDate.toISOString(), - }); - if (!this.logs) { - this.logs = logs; - } - else if (logs) { - this.newLogs = `${this.newLogs}\n${logs}`.trim(); - } - } catch (error) { - this.logs = [ - _i18n._(t`Failed to load logs: ${error.message}`), - _i18n._(t`Reason: ${error.reason} (${error.code})`), - ].join("\n") - } - this.logsReady = true; - } - - reload = async () => { - this.resetLogs(); - this.refresher.stop(); - await this.load(); - this.refresher.start(); - } - - componentDidUpdate() { - // scroll logs only when it's already in the end, - // otherwise it can interrupt reading by jumping after loading new logs update - if (this.logsArea && this.lastLineIsShown) { - this.logsArea.scrollTop = this.logsArea.scrollHeight; - } - } - - onScroll = (evt: React.UIEvent) => { - const logsArea = evt.currentTarget; - const { scrollHeight, clientHeight, scrollTop } = logsArea; - this.lastLineIsShown = clientHeight + scrollTop === scrollHeight; - }; - - getLogs() { - const { logs, newLogs, showTimestamps } = this; - return { - logs: showTimestamps ? logs : this.removeTimestamps(logs), - newLogs: showTimestamps ? newLogs : this.removeTimestamps(newLogs), - } - } - - getTimestamps(logs: string) { - return logs.match(/^\d+\S+/gm); - } - - removeTimestamps(logs: string) { - return logs.replace(/^\d+.*?\s/gm, ""); - } - - resetLogs() { - this.logs = ""; - this.newLogs = ""; - this.lastLineIsShown = true; - this.logsReady = false; - } - - onContainerChange = (option: SelectOption) => { - this.selectedContainer = this.containers - .concat(this.initContainers) - .find(container => container.name === option.value); - this.reload(); - } - - onTailLineChange = (option: SelectOption) => { - this.tailLines = option.value; - this.reload(); - } - - formatOptionLabel = (option: SelectOption) => { - const { value, label } = option; - return label || <> {value}; - } - - toggleTimestamps = () => { - this.showTimestamps = !this.showTimestamps; - } - - downloadLogs = () => { - const { logs, newLogs } = this.getLogs(); - const fileName = this.selectedContainer.name + ".log"; - const fileContents = logs + newLogs; - downloadFile(fileName, fileContents, "text/plain"); - } - - get containerSelectOptions() { - return [ - { - label: _i18n._(t`Containers`), - options: this.containers.map(container => { - return { value: container.name } - }), - }, - { - label: _i18n._(t`Init Containers`), - options: this.initContainers.map(container => { - return { value: container.name } - }), - } - ]; - } - - renderControlsPanel() { - const { logsReady, showTimestamps } = this; - if (!logsReady) return; - const timestamps = this.getTimestamps(this.logs + this.newLogs); - let from = ""; - let to = ""; - if (timestamps) { - from = new Date(timestamps[0]).toLocaleString(); - to = new Date(timestamps[timestamps.length - 1]).toLocaleString(); - } - return ( -
-
- {timestamps && From {from} to {to}} -
-
- - -
-
- ) - } - - renderLogs() { - if (!this.logsReady) { - return - } - const { logs, newLogs } = this.getLogs(); - if (!logs && !newLogs) { - return

There are no logs available for container.

- } - return ( - <> -
- {newLogs && ( - <> -

-

- - )} - - ); - } - - render() { - const { ...dialogProps } = this.props; - const { selectedContainer, tailLines } = this; - const podName = this.data ? this.data.pod.getName() : ""; - const header =
{podName} Logs
; - return ( - - - Close}> -
-
- Container - {selectedContainer && ( - -
- {this.renderControlsPanel()} -
-
this.logsArea = e}> - {this.renderLogs()} -
-
-
-
- ) - } -} diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index aee156ff31..086422ee00 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -82,7 +82,6 @@ export class App extends React.Component { -