From 2a076e09454ee0d768ea07f76190843c0e0b6a70 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 21 Oct 2022 10:02:14 -0700 Subject: [PATCH 01/20] refactor: Extract pod log view buttons Signed-off-by: Alex Collins --- .../pod-logs-viewer/container-selector.tsx | 46 ++++ .../pod-logs-viewer/copy-logs-button.tsx | 65 ++++++ .../dark-mode-toggle-button.tsx | 18 ++ .../pod-logs-viewer/download-logs-button.tsx | 32 +++ .../pod-logs-viewer/follow-toggle-button.tsx | 28 +++ .../pod-logs-viewer/fullscreen-button.tsx | 29 +++ .../components/pod-logs-viewer/log-loader.ts | 4 + .../pod-logs-viewer/pod-logs-viewer.tsx | 212 ++---------------- .../show-previous-logs-toggle-button.tsx | 19 ++ .../timestamps-toggle-button.tsx | 25 +++ .../wrap-lines-toggle-button.tsx | 15 ++ 11 files changed, 304 insertions(+), 189 deletions(-) create mode 100644 ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/log-loader.ts create mode 100644 ui/src/app/applications/components/pod-logs-viewer/show-previous-logs-toggle-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx diff --git a/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx b/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx new file mode 100644 index 0000000000000..be1d65509c0a8 --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx @@ -0,0 +1,46 @@ +import {DropDownMenu, Tooltip} from "argo-ui"; +import * as React from "react"; + +type ContainerGroup = { offset: number, containers: String[] }; +export const ContainerSelector = ({ + containerGroups, + containerName, + onClickContainer + }: { containerGroups: ContainerGroup[], containerName: string, onClickContainer: (group: ContainerGroup, index: number, logs: String) => void }) => { + const containerItems: { title: any; action: () => any }[] = []; + if (containerGroups?.length > 0) { + containerGroups.forEach(group => { + containerItems.push({ + title: group.offset === 0 ? 'CONTAINER' : 'INIT CONTAINER', + action: null + }); + + group.containers.forEach((container: any, index: number) => { + const title = ( +
+ {container.name === containerName && } + + {container.name.toUpperCase()} + +
+ ); + containerItems.push({ + title, + action: () => (container.name === containerName ? {} : onClickContainer(group, index, 'logs')) + }); + }); + }); + } + return containerGroups?.length > 0 && ( + ( + + + + )} + items={containerItems} + /> + ) +} \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx new file mode 100644 index 0000000000000..f49a01cee1190 --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx @@ -0,0 +1,65 @@ +import * as React from "react"; +import {Tooltip} from "argo-ui"; +import {useState} from "react"; +import {LogLoader} from "./log-loader"; + +export const CopyLogsButton = ({ + loader, + }: { loader: LogLoader}) => { + + const [copy, setCopy] = useState(''); + const setColor = (i: string) => { + const element = document.getElementById('copyButton'); + if (i === 'success') { + element.classList.remove('copyStandard'); + element.classList.add('copySuccess'); + } else if (i === 'failure') { + element.classList.remove('copyStandard'); + element.classList.add('copyFailure'); + } else { + element.classList.remove('copySuccess'); + element.classList.remove('copyFailure'); + element.classList.add('copyStandard'); + } + }; + return + + +} \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx new file mode 100644 index 0000000000000..5a59e4f69a889 --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx @@ -0,0 +1,18 @@ +import {Tooltip} from "argo-ui"; +import {services, ViewPreferences} from "../../../shared/services"; +import * as React from "react"; + +export const DarkModeToggleButton = ({prefs}: { prefs: ViewPreferences }) => + + \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx new file mode 100644 index 0000000000000..688b85f7e7cfa --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx @@ -0,0 +1,32 @@ +import {Tooltip} from "argo-ui"; +import {services} from "../../../shared/services"; +import * as React from "react"; +import {PodLogsProps} from "./pod-logs-viewer"; + +export const DownloadLogsButton = ({ + applicationName, + applicationNamespace, + containerName, + group, + kind, + name, + namespace, + podName + }: PodLogsProps) => + + + \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx new file mode 100644 index 0000000000000..14798e124669a --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx @@ -0,0 +1,28 @@ +import {Checkbox, Tooltip} from "argo-ui"; +import * as classNames from "classnames"; +import {services, ViewPreferences} from "../../../shared/services"; +import * as React from "react"; +import {LogLoader} from "./log-loader"; + +export const FollowToggleButton = ({prefs, page, setPage, loader}:{page:{number:number}, + setPage:(page:{number:number,untilTimes:[]}) => void, + prefs:ViewPreferences,loader:LogLoader}) => + + \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx new file mode 100644 index 0000000000000..c27b2b7d8bfc2 --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx @@ -0,0 +1,29 @@ +import {Tooltip} from "argo-ui"; +import {Link} from "react-router-dom"; +import * as React from "react"; +import {PodLogsProps} from "./pod-logs-viewer"; + +export const FullscreenButton = ({ + applicationName, + applicationNamespace, + containerName, + fullscreen, + group, + kind, + name, + namespace, + podName + }: PodLogsProps & { fullscreen?: boolean }) => { + const fullscreenURL = + `/applications/${applicationNamespace}/${applicationName}/${namespace}/${containerName}/logs?` + + `podName=${podName}&group=${group}&kind=${kind}&name=${name}`; + return !fullscreen && ( + + + + ) +} \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/log-loader.ts b/ui/src/app/applications/components/pod-logs-viewer/log-loader.ts new file mode 100644 index 0000000000000..7c9b011a7c451 --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/log-loader.ts @@ -0,0 +1,4 @@ +import {DataLoader} from "argo-ui"; +import * as models from "../../../shared/models"; + +export type LogLoader = DataLoader; \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx index d5409e9dd7f90..754ee05da82cf 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx @@ -6,11 +6,21 @@ import {Link} from 'react-router-dom'; import {bufferTime, delay, filter as rxfilter, map, retryWhen, scan} from 'rxjs/operators'; import Ansi from 'ansi-to-react'; import * as models from '../../../shared/models'; -import {services} from '../../../shared/services'; +import {services, ViewPreferences} from '../../../shared/services'; import {BASE_COLORS} from '../utils'; import './pod-logs-viewer.scss'; +import {CopyLogsButton} from "./copy-logs-button"; +import {DownloadLogsButton} from "./download-logs-button"; +import {ContainerSelector} from "./container-selector"; +import {FollowToggleButton} from "./follow-toggle-button"; +import {WrapLinesToggleButton} from "./wrap-lines-toggle-button"; +import {LogLoader} from "./log-loader"; +import {ShowPreviousLogsToggleButton} from "./show-previous-logs-toggle-button"; +import {TimestampsToggleButton} from "./timestamps-toggle-button"; +import {DarkModeToggleButton} from "./dark-mode-toggle-button"; +import {FullscreenButton} from "./fullscreen-button"; const maxLines = 100; export interface PodLogsProps { @@ -35,8 +45,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => return
Pod does not have container with name {props.containerName}
; } - let loader: DataLoader; - const [copy, setCopy] = useState(''); + let loader: LogLoader; const [selectedLine, setSelectedLine] = useState(-1); const bottom = React.useRef(null); const top = React.useRef(null); @@ -46,30 +55,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => const [viewTimestamps, setViewTimestamps] = useState(false); const [showPreviousLogs, setPreviousLogs] = useState(false); - const containerItems: {title: any; action: () => any}[] = []; - if (props.containerGroups?.length > 0) { - props.containerGroups.forEach(group => { - containerItems.push({ - title: group.offset === 0 ? 'CONTAINER' : 'INIT CONTAINER', - action: null - }); - group.containers.forEach((container: any, index: number) => { - const title = ( -
- {container.name === containerName && } - - {container.name.toUpperCase()} - -
- ); - containerItems.push({ - title, - action: () => (container.name === containerName ? {} : onClickContainer(group, index, 'logs')) - }); - }); - }); - } interface FilterData { literal: string; inverse: boolean; @@ -97,174 +83,22 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => return () => clearTimeout(to); }, [filterText]); - const setColor = (i: string) => { - const element = document.getElementById('copyButton'); - if (i === 'success') { - element.classList.remove('copyStandard'); - element.classList.add('copySuccess'); - } else if (i === 'failure') { - element.classList.remove('copyStandard'); - element.classList.add('copyFailure'); - } else { - element.classList.remove('copySuccess'); - element.classList.remove('copyFailure'); - element.classList.add('copyStandard'); - } - }; - const fullscreenURL = - `/applications/${props.applicationNamespace}/${props.applicationName}/${props.namespace}/${props.containerName}/logs?` + - `podName=${props.podName}&group=${props.group}&kind=${props.kind}&name=${props.name}`; + return ( services.viewPreferences.getPreferences()}> - {prefs => ( + {(prefs:ViewPreferences) => (
- - - - - - - {props.containerGroups?.length > 0 && ( - ( - - - - )} - items={containerItems} - /> - )} - - - - - - - - - - - - - {!props.timestamp && ( - - - - )} - {!props.fullscreen && ( - - - - )} + + + + + + + + +
diff --git a/ui/src/app/applications/components/pod-logs-viewer/show-previous-logs-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/show-previous-logs-toggle-button.tsx new file mode 100644 index 0000000000000..ef55efd08bf73 --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/show-previous-logs-toggle-button.tsx @@ -0,0 +1,19 @@ +import {Checkbox, Tooltip} from "argo-ui"; +import * as React from "react"; +import {LogLoader} from "./log-loader"; + +export const ShowPreviousLogsToggleButton = ({setPreviousLogs, showPreviousLogs, loader}: { + setPreviousLogs: (value: boolean) => void, + showPreviousLogs: boolean, + loader: LogLoader, +}) => + + \ No newline at end of file diff --git a/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx new file mode 100644 index 0000000000000..8d2dd673528dd --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx @@ -0,0 +1,25 @@ +import {Checkbox, Tooltip} from "argo-ui"; +import * as React from "react"; + +export const TimestampsToggleButton = ({ + timestamp, + viewTimestamps, + setViewTimestamps, + viewPodNames, + setViewPodNames + }: { timestamp?: string, viewTimestamps: boolean, setViewTimestamps: (value: boolean) => void, viewPodNames: boolean, setViewPodNames: (value: boolean) => void }) => + !timestamp && ( + + + + ) diff --git a/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx new file mode 100644 index 0000000000000..7ceedb16b5e9a --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx @@ -0,0 +1,15 @@ +import {Checkbox, Tooltip} from "argo-ui"; +import {services, ViewPreferences} from "../../../shared/services"; +import * as React from "react"; + +export const WrapLinesToggleButton = ({prefs}: { prefs: ViewPreferences }) => + + \ No newline at end of file From d283cada54cedce032c1f4894947791caa5dd360 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 21 Oct 2022 11:01:30 -0700 Subject: [PATCH 02/20] feat: add - - )} - items={containerItems} - /> - ) -} \ No newline at end of file + return ( + containerGroups?.length > 0 && ( + ( + + )} + items={containerItems} + /> + ) + ); +}; diff --git a/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx index f49a01cee1190..726e85f93f0df 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/copy-logs-button.tsx @@ -1,31 +1,16 @@ -import * as React from "react"; -import {Tooltip} from "argo-ui"; -import {useState} from "react"; -import {LogLoader} from "./log-loader"; +import * as React from 'react'; +import {useContext} from 'react'; +import {LogLoader} from './log-loader'; +import {Button} from '../../../shared/components/button'; +import {Context} from '../../../shared/context'; +import {NotificationType} from 'argo-ui/src/components/notifications/notifications'; -export const CopyLogsButton = ({ - loader, - }: { loader: LogLoader}) => { - - const [copy, setCopy] = useState(''); - const setColor = (i: string) => { - const element = document.getElementById('copyButton'); - if (i === 'success') { - element.classList.remove('copyStandard'); - element.classList.add('copySuccess'); - } else if (i === 'failure') { - element.classList.remove('copyStandard'); - element.classList.add('copyFailure'); - } else { - element.classList.remove('copySuccess'); - element.classList.remove('copyFailure'); - element.classList.add('copyStandard'); - } - }; - return - - -} \ No newline at end of file + }} + /> + ); +}; diff --git a/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx index 5a59e4f69a889..6e4410835125b 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/dark-mode-toggle-button.tsx @@ -1,18 +1,18 @@ -import {Tooltip} from "argo-ui"; -import {services, ViewPreferences} from "../../../shared/services"; -import * as React from "react"; +import {services, ViewPreferences} from '../../../shared/services'; +import * as React from 'react'; +import {ToggleButton} from '../../../shared/components/toggle-button'; -export const DarkModeToggleButton = ({prefs}: { prefs: ViewPreferences }) => - - \ No newline at end of file + }} + toggled={prefs.appDetails.darkMode} + icon='moon' + /> +); diff --git a/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx index 688b85f7e7cfa..d2191c271b837 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/download-logs-button.tsx @@ -1,32 +1,15 @@ -import {Tooltip} from "argo-ui"; -import {services} from "../../../shared/services"; -import * as React from "react"; -import {PodLogsProps} from "./pod-logs-viewer"; +import {services} from '../../../shared/services'; +import * as React from 'react'; +import {PodLogsProps} from './pod-logs-viewer'; +import {Button} from '../../../shared/components/button'; -export const DownloadLogsButton = ({ - applicationName, - applicationNamespace, - containerName, - group, - kind, - name, - namespace, - podName - }: PodLogsProps) => - - - \ No newline at end of file +export const DownloadLogsButton = ({applicationName, applicationNamespace, containerName, group, kind, name, namespace, podName}: PodLogsProps) => ( + - \ No newline at end of file + }} + toggled={prefs.appDetails.followLogs} + icon='turn-down' + /> +); diff --git a/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx index c27b2b7d8bfc2..82a61517b010a 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/fullscreen-button.tsx @@ -1,29 +1,26 @@ -import {Tooltip} from "argo-ui"; -import {Link} from "react-router-dom"; -import * as React from "react"; -import {PodLogsProps} from "./pod-logs-viewer"; +import {Link} from 'react-router-dom'; +import * as React from 'react'; +import {PodLogsProps} from './pod-logs-viewer'; +import {Button} from '../../../shared/components/button'; export const FullscreenButton = ({ - applicationName, - applicationNamespace, - containerName, - fullscreen, - group, - kind, - name, - namespace, - podName - }: PodLogsProps & { fullscreen?: boolean }) => { + applicationName, + applicationNamespace, + containerName, + fullscreen, + group, + kind, + name, + namespace, + podName +}: PodLogsProps & {fullscreen?: boolean}) => { const fullscreenURL = - `/applications/${applicationNamespace}/${applicationName}/${namespace}/${containerName}/logs?` + - `podName=${podName}&group=${group}&kind=${kind}&name=${name}`; - return !fullscreen && ( - - - - ) -} \ No newline at end of file + `/applications/${applicationNamespace}/${applicationName}/${namespace}/${containerName}/logs?` + `podName=${podName}&group=${group}&kind=${kind}&name=${name}`; + return ( + !fullscreen && ( + + - \ No newline at end of file + }} + icon='backward' + toggled={showPreviousLogs} + /> +); diff --git a/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx index 8d2dd673528dd..6b3d03ca60945 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/timestamps-toggle-button.tsx @@ -1,25 +1,29 @@ -import {Checkbox, Tooltip} from "argo-ui"; -import * as React from "react"; +import * as React from 'react'; +import {ToggleButton} from '../../../shared/components/toggle-button'; export const TimestampsToggleButton = ({ - timestamp, - viewTimestamps, - setViewTimestamps, - viewPodNames, - setViewPodNames - }: { timestamp?: string, viewTimestamps: boolean, setViewTimestamps: (value: boolean) => void, viewPodNames: boolean, setViewPodNames: (value: boolean) => void }) => + timestamp, + viewTimestamps, + setViewTimestamps, + viewPodNames, + setViewPodNames +}: { + timestamp?: string; + viewTimestamps: boolean; + setViewTimestamps: (value: boolean) => void; + viewPodNames: boolean; + setViewPodNames: (value: boolean) => void; +}) => !timestamp && ( - - - - ) + { + setViewTimestamps(!viewTimestamps); + if (viewPodNames) { + setViewPodNames(false); + } + }} + toggled={viewTimestamps} + icon='clock' + /> + ); diff --git a/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx index 7ceedb16b5e9a..ea35911ad3c46 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/wrap-lines-toggle-button.tsx @@ -1,15 +1,15 @@ -import {Checkbox, Tooltip} from "argo-ui"; -import {services, ViewPreferences} from "../../../shared/services"; -import * as React from "react"; +import {services, ViewPreferences} from '../../../shared/services'; +import * as React from 'react'; +import {ToggleButton} from '../../../shared/components/toggle-button'; -export const WrapLinesToggleButton = ({prefs}: { prefs: ViewPreferences }) => - - \ No newline at end of file + }} + toggled={prefs.appDetails.wrapLines} + icon='paragraph' + /> +); diff --git a/ui/src/app/shared/components/button.tsx b/ui/src/app/shared/components/button.tsx new file mode 100644 index 0000000000000..85c8bca847e81 --- /dev/null +++ b/ui/src/app/shared/components/button.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import {MouseEventHandler, ReactNode} from 'react'; +import {Icon} from './icon'; +import {Tooltip} from 'argo-ui'; + +export const Button = ({ + onClick, + children, + title, + outline, + icon, + className, + disabled +}: { + onClick?: MouseEventHandler; + children?: ReactNode; + title?: string; + outline?: boolean; + icon?: Icon; + className?: string; + disabled?: boolean; +}) => ( + + + +); diff --git a/ui/src/app/shared/components/icon.ts b/ui/src/app/shared/components/icon.ts new file mode 100644 index 0000000000000..3a2afc6250298 --- /dev/null +++ b/ui/src/app/shared/components/icon.ts @@ -0,0 +1 @@ +export type Icon = string; diff --git a/ui/src/app/shared/components/toggle-button.tsx b/ui/src/app/shared/components/toggle-button.tsx new file mode 100644 index 0000000000000..355ec58517d81 --- /dev/null +++ b/ui/src/app/shared/components/toggle-button.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import {ReactNode} from 'react'; +import {Button} from './button'; +import {Icon} from './icon'; + +export const ToggleButton = ({ + title, + children, + onToggle, + toggled, + disabled, + icon +}: { + toggled: boolean; + onToggle: () => void; + children?: ReactNode; + title: string; + disabled?: boolean; + icon: Icon; +}) => ( + +); From 646ea7311524a7ace0b3a52beb669a0dd75ba43a Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 21 Oct 2022 11:35:17 -0700 Subject: [PATCH 03/20] feat: re-order buttons --- .../pod-logs-viewer/pod-logs-viewer.scss | 4 +- .../pod-logs-viewer/pod-logs-viewer.tsx | 86 +++++++++++-------- ui/src/app/shared/components/button-group.tsx | 11 +++ ui/src/app/shared/components/button.tsx | 5 +- .../app/shared/components/toggle-button.tsx | 11 ++- 5 files changed, 75 insertions(+), 42 deletions(-) create mode 100644 ui/src/app/shared/components/button-group.tsx diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss index bf2264ddc57e8..5c955c0943b90 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss @@ -68,13 +68,13 @@ i { cursor: pointer; border-radius: 7px; - $size: 25px; + $size: 22px; width: $size; height: $size; display: flex; align-items: center; justify-content: center; - border: 1px solid black; + border: 1px solid gray; margin: 0 2px; &:hover { background-color: black; diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx index 59b08a456a82e..61aa8cc4d8513 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx @@ -1,4 +1,4 @@ -import {DataLoader, DropDownMenu, Tooltip, Checkbox} from 'argo-ui'; +import {DataLoader, DropDownMenu, Tooltip} from 'argo-ui'; import * as classNames from 'classnames'; import * as React from 'react'; import {useRef, useState} from 'react'; @@ -20,6 +20,8 @@ import {ShowPreviousLogsToggleButton} from './show-previous-logs-toggle-button'; import {TimestampsToggleButton} from './timestamps-toggle-button'; import {DarkModeToggleButton} from './dark-mode-toggle-button'; import {FullscreenButton} from './fullscreen-button'; +import {ButtonGroup} from '../../../shared/components/button-group'; +import {ToggleButton} from '../../../shared/components/toggle-button'; const maxLines = 100; export interface PodLogsProps { @@ -89,32 +91,35 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => {(prefs: ViewPreferences) => (
- - - - - - - - - + + + + + + + + + + + + + + +
- - - + setFilter({...filter, inverse: !filter.inverse})} + title='Show lines that do not match' + icon='exclamation' + /> { return (
- {actions.begin && null)} />} - null)} /> - null)} /> - null)} /> -
- {info && ( - - Page {info.curPage + 1} (Lines {info.firstLine} to {info.lastLine}) - - )} -
- 0 ? '' : 'disabled'}`} onClick={(info && info.curPage > 0 && actions.right) || null} /> - 1 ? '' : 'disabled'}`} onClick={(info && info.curPage > 1 && actions.end) || null} /> + <> + <> + Lines {info?.firstLine} to {info?.lastLine}  + + + + +
+ <> + <> + Page {info?.curPage + 1} +   + + + + 0 ? '' : 'disabled'}`} onClick={actions.right} /> + 1 ? '' : 'disabled'}`} onClick={actions.end} /> +
); }; diff --git a/ui/src/app/shared/components/button-group.tsx b/ui/src/app/shared/components/button-group.tsx new file mode 100644 index 0000000000000..ad1a3b6f068c4 --- /dev/null +++ b/ui/src/app/shared/components/button-group.tsx @@ -0,0 +1,11 @@ +import {ReactNode} from 'react'; +import * as React from 'react'; + +export const ButtonGroup = ({children}: {children: ReactNode}) => ( + + {children} + +); diff --git a/ui/src/app/shared/components/button.tsx b/ui/src/app/shared/components/button.tsx index 85c8bca847e81..9acf2beeab524 100644 --- a/ui/src/app/shared/components/button.tsx +++ b/ui/src/app/shared/components/button.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import {MouseEventHandler, ReactNode} from 'react'; +import {CSSProperties, MouseEventHandler, ReactNode} from 'react'; import {Icon} from './icon'; import {Tooltip} from 'argo-ui'; @@ -10,6 +10,7 @@ export const Button = ({ outline, icon, className, + style, disabled }: { onClick?: MouseEventHandler; @@ -18,11 +19,13 @@ export const Button = ({ outline?: boolean; icon?: Icon; className?: string; + style?: CSSProperties; disabled?: boolean; }) => ( diff --git a/ui/src/app/shared/components/toggle-button.tsx b/ui/src/app/shared/components/toggle-button.tsx index 355ec58517d81..cbc5c36fb9cc1 100644 --- a/ui/src/app/shared/components/toggle-button.tsx +++ b/ui/src/app/shared/components/toggle-button.tsx @@ -18,7 +18,16 @@ export const ToggleButton = ({ disabled?: boolean; icon: Icon; }) => ( - ); From cd0e65a7d5bbfe672343c7a2671864ca7fdecc02 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 21 Oct 2022 11:50:45 -0700 Subject: [PATCH 04/20] feat: add highlighting matched literal --- .../components/pod-logs-viewer/pod-logs-viewer.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx index 61aa8cc4d8513..04155d0c26ae2 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx @@ -85,6 +85,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => const loaderRef = useRef(); const loader: LogLoader = loaderRef.current; + const grep = filter.literal.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); //https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript return ( services.viewPreferences.getPreferences()}> @@ -178,7 +179,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => } return logsSource; }}> - {logs => { + {(logs:any[]) => { logs = logs || []; setTimeout(() => { if (page.number === 0 && prefs.appDetails.followLogs && bottom.current) { @@ -316,7 +317,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => )}
{lineNum}
- {l} + {l.replace(new RegExp(grep, 'g'), (y:string) => '\u001b[1m\u001b[43;1m\u001b[37m' + y + '\u001b[0m')}
); From 7828317f87430d5c21fddeec8a411fdb10d12edd Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 21 Oct 2022 11:59:35 -0700 Subject: [PATCH 05/20] feat: added spacer.tsx --- .../components/pod-logs-viewer/pod-logs-viewer.tsx | 3 +++ ui/src/app/shared/components/button-group.tsx | 7 +------ ui/src/app/shared/components/spacer.tsx | 3 +++ 3 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 ui/src/app/shared/components/spacer.tsx diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx index 04155d0c26ae2..a7e8845de7ac4 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx @@ -22,6 +22,7 @@ import {DarkModeToggleButton} from './dark-mode-toggle-button'; import {FullscreenButton} from './fullscreen-button'; import {ButtonGroup} from '../../../shared/components/button-group'; import {ToggleButton} from '../../../shared/components/toggle-button'; +import { Spacer } from '../../../shared/components/spacer'; const maxLines = 100; export interface PodLogsProps { @@ -95,6 +96,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => + + diff --git a/ui/src/app/shared/components/button-group.tsx b/ui/src/app/shared/components/button-group.tsx index ad1a3b6f068c4..fa3008df812c4 100644 --- a/ui/src/app/shared/components/button-group.tsx +++ b/ui/src/app/shared/components/button-group.tsx @@ -2,10 +2,5 @@ import {ReactNode} from 'react'; import * as React from 'react'; export const ButtonGroup = ({children}: {children: ReactNode}) => ( - - {children} - + {children} ); diff --git a/ui/src/app/shared/components/spacer.tsx b/ui/src/app/shared/components/spacer.tsx new file mode 100644 index 0000000000000..3eea7d9bed8fd --- /dev/null +++ b/ui/src/app/shared/components/spacer.tsx @@ -0,0 +1,3 @@ +import * as React from "react"; + +export const Spacer = () =>    \ No newline at end of file From 8e6c9fb469acbfb3db952162cd39214bba2a15ad Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 21 Oct 2022 18:27:42 -0700 Subject: [PATCH 06/20] feat: update options --- .../application-fullscreen-logs.tsx | 7 - .../pod-logs-viewer/container-selector.tsx | 2 +- .../components/pod-logs-viewer/filter.tsx | 14 + .../pod-logs-viewer/follow-toggle-button.tsx | 27 +- .../pod-logs-viewer/pod-logs-viewer.scss | 51 -- .../pod-logs-viewer/pod-logs-viewer.tsx | 543 ++++++++---------- .../pod-logs-viewer/tail-selector.tsx | 17 + .../pod-logs-viewer/time-range-selector.tsx | 27 + .../resource-details/resource-details.tsx | 5 - ui/src/app/shared/components/button-group.tsx | 6 - ui/src/app/shared/components/group.tsx | 4 + ui/src/app/shared/components/spacer.tsx | 4 +- .../shared/services/applications-service.ts | 62 +- 13 files changed, 328 insertions(+), 441 deletions(-) create mode 100644 ui/src/app/applications/components/pod-logs-viewer/filter.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/tail-selector.tsx create mode 100644 ui/src/app/applications/components/pod-logs-viewer/time-range-selector.tsx delete mode 100644 ui/src/app/shared/components/button-group.tsx create mode 100644 ui/src/app/shared/components/group.tsx diff --git a/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx b/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx index 4314d1e1c6a47..c7e669f46dded 100644 --- a/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx +++ b/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx @@ -3,12 +3,10 @@ import * as React from 'react'; import Helmet from 'react-helmet'; import {RouteComponentProps} from 'react-router-dom'; import {Query} from '../../../shared/components'; -import {Context} from '../../../shared/context'; import {PodsLogsViewer} from '../pod-logs-viewer/pod-logs-viewer'; import './application-fullscreen-logs.scss'; export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: string; appnamespace: string; container: string; namespace: string}>) => { - const appContext = React.useContext(Context); return ( {q => { @@ -16,8 +14,6 @@ export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: stri const name = q.get('name'); const group = q.get('group'); const kind = q.get('kind'); - const page = q.get('page'); - const untilTimes = (q.get('untilTimes') || '').split(',') || []; const title = `${podName || `${group}/${kind}/${name}`}:${props.match.params.container}`; return (
@@ -32,9 +28,6 @@ export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: stri kind={kind} name={name} podName={podName} - fullscreen={true} - page={{number: parseInt(page, 10) || 0, untilTimes}} - setPage={pageData => appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')}, {replace: true})} />
); diff --git a/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx b/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx index 0e95e04d6a8dd..2eb9491519088 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/container-selector.tsx @@ -41,7 +41,7 @@ export const ContainerSelector = ({ ( )} items={containerItems} diff --git a/ui/src/app/applications/components/pod-logs-viewer/filter.tsx b/ui/src/app/applications/components/pod-logs-viewer/filter.tsx new file mode 100644 index 0000000000000..4a4386c83235e --- /dev/null +++ b/ui/src/app/applications/components/pod-logs-viewer/filter.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; +import {HelpIcon, Tooltip} from 'argo-ui'; +import {Spacer} from '../../../shared/components/spacer'; + +export const Filter = ({filterText, setFilterText}: {filterText: string; setFilterText: (value: string) => void}) => ( + <> + + + + setFilterText(e.target.value)} /> + + + +); diff --git a/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx b/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx index 820255236ecdd..757eb5fe18f69 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/follow-toggle-button.tsx @@ -1,34 +1,13 @@ -import {services, ViewPreferences} from '../../../shared/services'; import * as React from 'react'; -import {LogLoader} from './log-loader'; import {ToggleButton} from '../../../shared/components/toggle-button'; -export const FollowToggleButton = ({ - prefs, - page, - setPage, - loader -}: { - page: {number: number}; - setPage: (page: {number: number; untilTimes: []}) => void; - prefs: ViewPreferences; - loader: LogLoader; -}) => ( +export const FollowToggleButton = ({follow, setFollow}: {follow: boolean; setFollow: (value: boolean) => void}) => ( 0} onToggle={() => { - if (page.number > 0) { - return; - } - const follow = !prefs.appDetails.followLogs; - services.viewPreferences.updatePreferences({...prefs, appDetails: {...prefs.appDetails, followLogs: follow}}); - if (follow) { - setPage({number: 0, untilTimes: []}); - } - loader.reload(); + setFollow(!follow); }} - toggled={prefs.appDetails.followLogs} + toggled={follow} icon='turn-down' /> ); diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss index 5c955c0943b90..00df1cbaf95d2 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.scss @@ -43,57 +43,6 @@ .argo-button { margin-right: 5px; border: 1px solid transparent; - - .fa { - width: 12px; - } - } - } - - &__filter { - display: flex; - margin-left: auto; - width: 320px; - - .argo-button { - display: flex; - align-items: center; - } - } - - &__menu { - display: flex; - margin-bottom: 1em; - padding-left: 10px; - i { - cursor: pointer; - border-radius: 7px; - $size: 22px; - width: $size; - height: $size; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid gray; - margin: 0 2px; - &:hover { - background-color: black; - color: white; - } - &.disabled { - opacity: 0.5; - cursor: not-allowed; - } - } - - &--inverted { - i { - border-color: white; - &:hover { - background-color: white; - color: black; - } - } } } diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx index a7e8845de7ac4..319900b02a3ef 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx @@ -1,7 +1,7 @@ import {DataLoader, DropDownMenu, Tooltip} from 'argo-ui'; import * as classNames from 'classnames'; import * as React from 'react'; -import {useRef, useState} from 'react'; +import {useEffect, useRef, useState} from 'react'; import {bufferTime, delay, filter as rxfilter, map, retryWhen, scan} from 'rxjs/operators'; import Ansi from 'ansi-to-react'; import * as models from '../../../shared/models'; @@ -20,11 +20,12 @@ import {ShowPreviousLogsToggleButton} from './show-previous-logs-toggle-button'; import {TimestampsToggleButton} from './timestamps-toggle-button'; import {DarkModeToggleButton} from './dark-mode-toggle-button'; import {FullscreenButton} from './fullscreen-button'; -import {ButtonGroup} from '../../../shared/components/button-group'; -import {ToggleButton} from '../../../shared/components/toggle-button'; -import { Spacer } from '../../../shared/components/spacer'; +import {Spacer} from '../../../shared/components/spacer'; +import {Filter} from './filter'; +import {Option, TimeRangeSelector} from './time-range-selector'; +import {TailSelector} from './tail-selector'; +import {Group} from '../../../shared/components/group'; -const maxLines = 100; export interface PodLogsProps { namespace: string; applicationNamespace: string; @@ -34,346 +35,252 @@ export interface PodLogsProps { group?: string; kind?: string; name?: string; - page: {number: number; untilTimes: string[]}; timestamp?: string; - setPage: (pageData: {number: number; untilTimes: string[]}) => void; containerGroups?: any[]; - onClickContainer?: (group: any, i: number, tab: string) => any; + onClickContainer?: (group: any, i: number, tab: string) => void; } -export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) => { - const {containerName, onClickContainer} = props; +export const PodsLogsViewer = (props: PodLogsProps) => { + const {containerName, onClickContainer, timestamp, containerGroups, applicationName, applicationNamespace, namespace, podName, group, kind, name} = props; if (!containerName || containerName === '') { - return
Pod does not have container with name {props.containerName}
; + return
Pod does not have container with name {containerName}
; } - const [selectedLine, setSelectedLine] = useState(-1); - const bottom = React.useRef(null); - const top = React.useRef(null); - const page = props.page; - const setPage = props.setPage; - const [viewPodNames, setViewPodNames] = useState(false); - const [viewTimestamps, setViewTimestamps] = useState(false); - const [showPreviousLogs, setPreviousLogs] = useState(false); + const queryParams = new URLSearchParams(location.search); + const [selectedLine, setSelectedLine] = useState(parseInt(queryParams.get('selectedLine'), 10) || -1); + const [viewPodNames, setViewPodNames] = useState(queryParams.get('viewPodNames') === 'true'); + const [follow, setFollow] = useState(queryParams.get('follow') === 'true'); + const [viewTimestamps, setViewTimestamps] = useState(queryParams.get('viewTimestamps') === 'true'); + const [previous, setPreviousLogs] = useState(queryParams.get('showPreviousLogs') === 'true'); + const [tail, setTail] = useState(parseInt(queryParams.get('tail'), 10) || 100); + const [since, setSince] = useState