From 83ed44f67011dfbd3387016212b74b268e815a30 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Fri, 15 Jan 2021 11:34:11 +0300 Subject: [PATCH] Adding logs tab bottom toolbar (#1951) * Adding bottom toolbar to logs tab Signed-off-by: Alex Andreev * Making bottom toolbar responsive Signed-off-by: Alex Andreev * Using generic search input clear button Signed-off-by: Alex Andreev * Fixing log test selectors Signed-off-by: Alex Andreev --- integration/__tests__/app.tests.ts | 14 +- src/extensions/renderer-api/components.ts | 2 +- src/renderer/components/checkbox/checkbox.tsx | 2 +- src/renderer/components/dock/dock-tabs.tsx | 4 +- src/renderer/components/dock/dock.tsx | 6 +- src/renderer/components/dock/info-panel.scss | 1 - .../components/dock/log-controls.scss | 6 + src/renderer/components/dock/log-controls.tsx | 68 ++++++++++ .../dock/{pod-log-list.scss => log-list.scss} | 2 +- .../dock/{pod-log-list.tsx => log-list.tsx} | 16 ++- ...ntrols.scss => log-resource-selector.scss} | 2 +- .../components/dock/log-resource-selector.tsx | 66 +++++++++ .../{pod-log-search.scss => log-search.scss} | 7 +- .../{pod-log-search.tsx => log-search.tsx} | 13 +- .../dock/{pod-logs.store.ts => log.store.ts} | 8 +- .../dock/{pod-logs.tsx => logs.tsx} | 70 ++++++---- .../components/dock/pod-log-controls.tsx | 126 ------------------ 17 files changed, 223 insertions(+), 190 deletions(-) create mode 100644 src/renderer/components/dock/log-controls.scss create mode 100644 src/renderer/components/dock/log-controls.tsx rename src/renderer/components/dock/{pod-log-list.scss => log-list.scss} (99%) rename src/renderer/components/dock/{pod-log-list.tsx => log-list.tsx} (94%) rename src/renderer/components/dock/{pod-log-controls.scss => log-resource-selector.scss} (62%) create mode 100644 src/renderer/components/dock/log-resource-selector.tsx rename src/renderer/components/dock/{pod-log-search.scss => log-search.scss} (61%) rename src/renderer/components/dock/{pod-log-search.tsx => log-search.tsx} (85%) rename src/renderer/components/dock/{pod-logs.store.ts => log.store.ts} (96%) rename src/renderer/components/dock/{pod-logs.tsx => logs.tsx} (62%) delete mode 100644 src/renderer/components/dock/pod-log-controls.tsx diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index d68ab2f011..7182a13107 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -505,16 +505,16 @@ describe("Lens integration tests", () => { await app.client.waitForVisible(".Drawer"); await app.client.click(".drawer-title .Menu li:nth-child(2)"); // Check if controls are available - await app.client.waitForVisible(".PodLogs .VirtualList"); - await app.client.waitForVisible(".PodLogControls"); - await app.client.waitForVisible(".PodLogControls .SearchInput"); - await app.client.waitForVisible(".PodLogControls .SearchInput input"); + await app.client.waitForVisible(".Logs .VirtualList"); + await app.client.waitForVisible(".LogResourceSelector"); + await app.client.waitForVisible(".LogResourceSelector .SearchInput"); + await app.client.waitForVisible(".LogResourceSelector .SearchInput input"); // Search for semicolon await app.client.keys(":"); - await app.client.waitForVisible(".PodLogs .list span.active"); + await app.client.waitForVisible(".Logs .list span.active"); // Click through controls - await app.client.click(".PodLogControls .timestamps-icon"); - await app.client.click(".PodLogControls .undo-icon"); + await app.client.click(".LogControls .show-timestamps"); + await app.client.click(".LogControls .show-previous"); }); }); diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index 68dd5d6510..a9a519498b 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -38,4 +38,4 @@ export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; export { terminalStore, createTerminalTab } from "../../renderer/components/dock/terminal.store"; -export { createPodLogsTab } from "../../renderer/components/dock/pod-logs.store"; +export { createPodLogsTab } from "../../renderer/components/dock/log.store"; diff --git a/src/renderer/components/checkbox/checkbox.tsx b/src/renderer/components/checkbox/checkbox.tsx index 0831e6122f..f97740a874 100644 --- a/src/renderer/components/checkbox/checkbox.tsx +++ b/src/renderer/components/checkbox/checkbox.tsx @@ -30,7 +30,7 @@ export class Checkbox extends React.PureComponent { render() { const { label, inline, className, value, theme, children, ...inputProps } = this.props; - const componentClass = cssNames("Checkbox flex", className, { + const componentClass = cssNames("Checkbox flex align-center", className, { inline, checked: value, disabled: this.props.disabled, diff --git a/src/renderer/components/dock/dock-tabs.tsx b/src/renderer/components/dock/dock-tabs.tsx index 54451ddd89..6bf9280d59 100644 --- a/src/renderer/components/dock/dock-tabs.tsx +++ b/src/renderer/components/dock/dock-tabs.tsx @@ -7,7 +7,7 @@ import { DockTab } from "./dock-tab"; import { IDockTab } from "./dock.store"; import { isEditResourceTab } from "./edit-resource.store"; import { isInstallChartTab } from "./install-chart.store"; -import { isPodLogsTab } from "./pod-logs.store"; +import { isLogsTab } from "./log.store"; import { TerminalTab } from "./terminal-tab"; import { isTerminalTab } from "./terminal.store"; import { isUpgradeChartTab } from "./upgrade-chart.store"; @@ -33,7 +33,7 @@ export const DockTabs = ({ tabs, autoFocus, selectedTab, onChangeTab }: Props) = return } />; } - if (isPodLogsTab(tab)) { + if (isLogsTab(tab)) { return ; } }; diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index f02502eab7..c8adf82992 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -16,8 +16,8 @@ import { EditResource } from "./edit-resource"; import { isEditResourceTab } from "./edit-resource.store"; import { InstallChart } from "./install-chart"; import { isInstallChartTab } from "./install-chart.store"; -import { PodLogs } from "./pod-logs"; -import { isPodLogsTab } from "./pod-logs.store"; +import { Logs } from "./logs"; +import { isLogsTab } from "./log.store"; import { TerminalWindow } from "./terminal-window"; import { createTerminalTab, isTerminalTab } from "./terminal.store"; import { UpgradeChart } from "./upgrade-chart"; @@ -64,7 +64,7 @@ export class Dock extends React.Component { {isInstallChartTab(tab) && } {isUpgradeChartTab(tab) && } {isTerminalTab(tab) && } - {isPodLogsTab(tab) && } + {isLogsTab(tab) && } ); } diff --git a/src/renderer/components/dock/info-panel.scss b/src/renderer/components/dock/info-panel.scss index 23dcc52243..482dbee02d 100644 --- a/src/renderer/components/dock/info-panel.scss +++ b/src/renderer/components/dock/info-panel.scss @@ -2,7 +2,6 @@ @include hidden-scrollbar; background: $dockInfoBackground; - border-bottom: 1px solid $dockInfoBorderColor; padding: $padding $padding * 2; flex-shrink: 0; diff --git a/src/renderer/components/dock/log-controls.scss b/src/renderer/components/dock/log-controls.scss new file mode 100644 index 0000000000..e446cca235 --- /dev/null +++ b/src/renderer/components/dock/log-controls.scss @@ -0,0 +1,6 @@ +.LogControls { + @include hidden-scrollbar; + + background: $dockInfoBackground; + padding: $padding $padding * 2; +} \ No newline at end of file diff --git a/src/renderer/components/dock/log-controls.tsx b/src/renderer/components/dock/log-controls.tsx new file mode 100644 index 0000000000..cedff7fbb9 --- /dev/null +++ b/src/renderer/components/dock/log-controls.tsx @@ -0,0 +1,68 @@ +import "./log-controls.scss"; + +import React from "react"; +import { observer } from "mobx-react"; + +import { Pod } from "../../api/endpoints"; +import { cssNames, saveFileDialog } from "../../utils"; +import { IPodLogsData, podLogsStore } from "./log.store"; +import { Checkbox } from "../checkbox"; +import { Icon } from "../icon"; + +interface Props { + tabData: IPodLogsData + logs: string[] + save: (data: Partial) => void + reload: () => void +} + +export const LogControls = observer((props: Props) => { + const { tabData, save, reload, logs } = props; + const { showTimestamps, previous } = tabData; + const since = logs.length ? podLogsStore.getTimestamps(logs[0]) : null; + const pod = new Pod(tabData.pod); + + const toggleTimestamps = () => { + save({ showTimestamps: !showTimestamps }); + }; + + const togglePrevious = () => { + save({ previous: !previous }); + reload(); + }; + + const downloadLogs = () => { + const fileName = pod.getName(); + const logsToDownload = showTimestamps ? logs : podLogsStore.logsWithoutTimestamps; + + saveFileDialog(`${fileName}.log`, logsToDownload.join("\n"), "text/plain"); + }; + + return ( +
+
+ {since && `Logs from ${new Date(since[0]).toLocaleString()}`} +
+
+ + + +
+
+ ); +}); diff --git a/src/renderer/components/dock/pod-log-list.scss b/src/renderer/components/dock/log-list.scss similarity index 99% rename from src/renderer/components/dock/pod-log-list.scss rename to src/renderer/components/dock/log-list.scss index 9b923b520b..8a39dcf925 100644 --- a/src/renderer/components/dock/pod-log-list.scss +++ b/src/renderer/components/dock/log-list.scss @@ -1,4 +1,4 @@ -.PodLogList { +.LogList { --overlay-bg: #8cc474b8; --overlay-active-bg: orange; diff --git a/src/renderer/components/dock/pod-log-list.tsx b/src/renderer/components/dock/log-list.tsx similarity index 94% rename from src/renderer/components/dock/pod-log-list.tsx rename to src/renderer/components/dock/log-list.tsx index c876d0c362..74d64d2f58 100644 --- a/src/renderer/components/dock/pod-log-list.tsx +++ b/src/renderer/components/dock/log-list.tsx @@ -1,4 +1,4 @@ -import "./pod-log-list.scss"; +import "./log-list.scss"; import React from "react"; import AnsiUp from "ansi_up"; @@ -14,7 +14,7 @@ import { Button } from "../button"; import { Icon } from "../icon"; import { Spinner } from "../spinner"; import { VirtualList } from "../virtual-list"; -import { podLogsStore } from "./pod-logs.store"; +import { podLogsStore } from "./log.store"; interface Props { logs: string[] @@ -26,7 +26,7 @@ interface Props { const colorConverter = new AnsiUp(); @observer -export class PodLogList extends React.Component { +export class LogList extends React.Component { @observable isJumpButtonVisible = false; @observable isLastLineVisible = true; @@ -206,19 +206,23 @@ export class PodLogList extends React.Component { const rowHeights = new Array(this.logs.length).fill(this.lineHeight); if (isInitLoading) { - return ; + return ( +
+ +
+ ); } if (!this.logs.length) { return ( -
+
There are no logs available for container
); } return ( -
+
) => void + reload: () => void +} + +export const LogResourceSelector = observer((props: Props) => { + const { tabData, save, reload } = props; + const { selectedContainer, containers, initContainers } = tabData; + const pod = new Pod(tabData.pod); + + const onContainerChange = (option: SelectOption) => { + const { containers, initContainers } = tabData; + + save({ + selectedContainer: containers + .concat(initContainers) + .find(container => container.name === option.value) + }); + reload(); + }; + + const getSelectOptions = (containers: IPodContainer[]) => { + return containers.map(container => { + return { + value: container.name, + label: container.name + }; + }); + }; + + const containerSelectOptions = [ + { + label: `Containers`, + options: getSelectOptions(containers) + }, + { + label: `Init Containers`, + options: getSelectOptions(initContainers), + } + ]; + + return ( +
+ Namespace + Pod + Container + -
- {since && ( - <> - Since{" "} - {new Date(since[0]).toLocaleString()} - - )} -
-
- - - - -
-
- ); -});