Skip to content

Commit ad58692

Browse files
authored
Merge pull request #312 from devtron-labs/fix/expand-all-logs
fix: use react-keybind for logs resize button & expand all logs accordions
2 parents 984f6c5 + eff0bca commit ad58692

File tree

8 files changed

+125
-86
lines changed

8 files changed

+125
-86
lines changed

package-lock.json

Lines changed: 9 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "0.3.7",
3+
"version": "0.3.6-beta-5",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",
@@ -87,6 +87,7 @@
8787
"react-mde": "^11.5.0",
8888
"react-router": "^5.3.0",
8989
"react-router-dom": "^5.3.0",
90+
"react-keybind": "^0.9.4",
9091
"rxjs": "^7.8.1",
9192
"yaml": "^2.4.1"
9293
},

src/Common/Tooltip/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const KEYBOARD_KEYS_MAP = {
66
Control: isMacOS ? '⌘' : 'Ctrl',
77
Shift: '⇧',
88
F: 'F',
9+
E: 'E',
910
} as const
1011

1112
export type SupportedKeyboardKeysType = keyof typeof KEYBOARD_KEYS_MAP

src/Shared/Components/CICDHistory/History.components.tsx

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
*/
1616

1717
import Tippy from '@tippyjs/react'
18-
import { useEffect } from 'react'
18+
import { useCallback, useEffect } from 'react'
1919
import { useLocation } from 'react-router-dom'
20-
import { ClipboardButton, GenericEmptyState, extractImage, useKeyDown, useSuperAdmin } from '../../../Common'
20+
import { withShortcut, IWithShortcut } from 'react-keybind'
21+
import { ClipboardButton, GenericEmptyState, Tooltip, extractImage, useSuperAdmin } from '../../../Common'
2122
import { EMPTY_STATE_STATUS } from '../../constants'
2223
import { ReactComponent as DropDownIcon } from '../../../Assets/Icon/ic-chevron-down.svg'
2324
import { GitChangesType, LogResizeButtonType, ScrollerType } from './types'
@@ -27,53 +28,62 @@ import { ReactComponent as ZoomIn } from '../../../Assets/Icon/ic-fullscreen.svg
2728
import { ReactComponent as ZoomOut } from '../../../Assets/Icon/ic-exit-fullscreen.svg'
2829
import './cicdHistory.scss'
2930

30-
export const LogResizeButton = ({ fullScreenView, setFullScreenView }: LogResizeButtonType): JSX.Element => {
31-
const { pathname } = useLocation()
31+
export const LogResizeButton = withShortcut(
32+
({ fullScreenView, setFullScreenView, shortcut }: LogResizeButtonType & IWithShortcut): JSX.Element => {
33+
const { pathname } = useLocation()
3234

33-
const keys = useKeyDown()
35+
const toggleFullScreen = useCallback((): void => {
36+
// NOTE: need to use ref due to the problem of stale function reference after registering the callback
37+
setFullScreenView(!fullScreenView)
38+
}, [fullScreenView])
3439

35-
const toggleFullScreen = (): void => {
36-
setFullScreenView(!fullScreenView)
37-
}
40+
useEffect(() => {
41+
if (pathname.includes('/logs')) {
42+
shortcut.registerShortcut(toggleFullScreen, ['f'], 'ToggleFullscreen', 'Enter/Exit fullscreen')
43+
shortcut.registerShortcut(
44+
() => setFullScreenView(false),
45+
['Escape'],
46+
'ToggleFullscreen',
47+
'Enter/Exit fullscreen',
48+
)
49+
}
3850

39-
useEffect(() => {
40-
if (!pathname.includes('/logs')) {
41-
return
42-
}
43-
// eslint-disable-next-line default-case
44-
switch (keys.join('')) {
45-
case 'f':
46-
toggleFullScreen()
47-
break
48-
case 'Escape':
49-
setFullScreenView(false)
50-
break
51-
}
52-
}, [keys])
51+
return () => {
52+
shortcut.unregisterShortcut(['f'])
53+
shortcut.unregisterShortcut(['Escape'])
54+
}
55+
}, [pathname, toggleFullScreen])
5356

54-
return (
55-
pathname.includes('/logs') && (
56-
<Tippy
57-
placement="top"
58-
arrow={false}
59-
className="default-tt"
60-
content={fullScreenView ? 'Exit fullscreen (f)' : 'Enter fullscreen (f)'}
61-
>
62-
<div>
63-
{fullScreenView ? (
64-
<ZoomOut className="zoom zoom--out pointer dc__zi-4" onClick={toggleFullScreen} />
65-
) : (
66-
<ZoomIn className="zoom zoom--in pointer dc__zi-4" onClick={toggleFullScreen} />
67-
)}
68-
</div>
69-
</Tippy>
57+
return (
58+
pathname.includes('/logs') && (
59+
<Tooltip
60+
placement="left"
61+
shortcutKeyCombo={{
62+
text: fullScreenView ? 'Exit fullscreen' : 'Enter fullscreen',
63+
combo: ['F'] as const,
64+
}}
65+
>
66+
<button
67+
type="button"
68+
aria-label="Enter/Exit fullscreen view"
69+
className="zoom dc__zi-4 flex dc__transparent log-resize-button"
70+
onClick={toggleFullScreen}
71+
>
72+
{fullScreenView ? (
73+
<ZoomOut className="icon-dim-16 dc__no-shrink" />
74+
) : (
75+
<ZoomIn className="icon-dim-16 dc__no-shrink" />
76+
)}
77+
</button>
78+
</Tooltip>
79+
)
7080
)
71-
)
72-
}
81+
},
82+
)
7383

7484
export const Scroller = ({ scrollToTop, scrollToBottom, style }: ScrollerType): JSX.Element => (
7585
<div style={style} className="dc__element-scroller flex column top br-4">
76-
<Tippy className="default-tt" arrow={false} content="Scroll to Top">
86+
<Tippy className="default-tt" arrow={false} content="Scroll to Top" placement="left">
7787
<button
7888
className="flex"
7989
disabled={!scrollToTop}
@@ -84,7 +94,7 @@ export const Scroller = ({ scrollToTop, scrollToBottom, style }: ScrollerType):
8494
<DropDownIcon className="rotate" style={{ ['--rotateBy' as any]: '180deg' }} />
8595
</button>
8696
</Tippy>
87-
<Tippy className="default-tt" arrow={false} content="Scroll to Bottom">
97+
<Tippy className="default-tt" arrow={false} content="Scroll to Bottom" placement="left">
8898
<button
8999
className="flex"
90100
disabled={!scrollToBottom}

src/Shared/Components/CICDHistory/LogsRenderer.tsx

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
*/
1616

1717
import { useParams } from 'react-router-dom'
18-
import { useEffect, useMemo, useRef, useState } from 'react'
18+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
1919
import AnsiUp from 'ansi_up'
2020
import DOMPurify from 'dompurify'
2121
import { ANSI_UP_REGEX, ComponentSizeType } from '@Shared/constants'
2222
import { escapeRegExp } from '@Shared/Helpers'
2323
import { ReactComponent as ICExpandAll } from '@Icons/ic-expand-all.svg'
2424
import { ReactComponent as ICCollapseAll } from '@Icons/ic-collapse-all.svg'
25+
import { withShortcut, IWithShortcut } from 'react-keybind'
2526
import {
2627
Progressing,
2728
Host,
@@ -30,7 +31,6 @@ import {
3031
ROUTES,
3132
SearchBar,
3233
useUrlFilters,
33-
stopPropagation,
3434
Tooltip,
3535
} from '../../../Common'
3636
import LogStageAccordion from './LogStageAccordion'
@@ -170,12 +170,13 @@ const useCIEventSource = (url: string, maxLength?: number): [string[], EventSour
170170
return [dataVal, eventSourceRef.current, logsNotAvailableError]
171171
}
172172

173-
export const LogsRenderer = ({
173+
const LogsRenderer = ({
174174
triggerDetails,
175175
isBlobStorageConfigured,
176176
parentType,
177177
fullScreenView,
178-
}: LogsRendererType): JSX.Element => {
178+
shortcut,
179+
}: LogsRendererType & IWithShortcut) => {
179180
const { pipelineId, envId, appId } = useParams<DeploymentHistoryBaseParamsType>()
180181
const logsURL =
181182
parentType === HistoryComponentType.CI
@@ -384,6 +385,28 @@ export const LogsRenderer = ({
384385
// And for other cases we would use handleSearchEnter
385386
}, [streamDataList, areEventsProgressing])
386387

388+
const handleToggleOpenAllStages = useCallback(() => {
389+
setStageList((prev) =>
390+
prev.map((stage) => ({
391+
...stage,
392+
isOpen: !areAllStagesExpanded,
393+
})),
394+
)
395+
}, [areAllStagesExpanded])
396+
397+
useEffect(() => {
398+
shortcut.registerShortcut(
399+
handleToggleOpenAllStages,
400+
['e'],
401+
'ExpandCollapseLogStages',
402+
'Expand/Collapse all log stages',
403+
)
404+
405+
return () => {
406+
shortcut.unregisterShortcut(['e'])
407+
}
408+
}, [handleToggleOpenAllStages])
409+
387410
const handleSearchEnter = (searchText: string) => {
388411
handleSearch(searchText)
389412
const newStageList = getStageListFromStreamData(searchText)
@@ -402,15 +425,6 @@ export const LogsRenderer = ({
402425
setStageList(newLogs)
403426
}
404427

405-
const handleToggleOpenAllStages = () => {
406-
setStageList(
407-
stageList.map((stage) => ({
408-
...stage,
409-
isOpen: !areAllStagesExpanded,
410-
})),
411-
)
412-
}
413-
414428
const renderLogs = () => {
415429
if (areStagesAvailable) {
416430
return (
@@ -427,11 +441,7 @@ export const LogsRenderer = ({
427441
backgroundColor: '#0C1021',
428442
}}
429443
>
430-
<div
431-
className="flexbox logs-renderer__search-bar logs-renderer__filters-border-bottom pl-12"
432-
// Doing this since we have binded 'f' with full screen and SearchVar has not exposed event on search, so on pressing f it goes to full screen
433-
onKeyDown={stopPropagation}
434-
>
444+
<div className="flexbox logs-renderer__search-bar logs-renderer__filters-border-bottom pl-12">
435445
<SearchBar
436446
noBackgroundAndBorder
437447
containerClassName="w-100"
@@ -445,16 +455,17 @@ export const LogsRenderer = ({
445455
<Tooltip
446456
shortcutKeyCombo={{
447457
text: areAllStagesExpanded ? 'Collapse all stages' : 'Expand all stages',
448-
combo: ['Control', 'Shift', 'F'] as const,
458+
combo: ['E'] as const,
449459
}}
450460
className="dc__mxw-500"
451461
placement="left"
452462
>
453463
<button
454464
type="button"
455-
className="dc__unset-button-styles px-10 flex dc__bg-n0--opacity-0_2"
465+
className="dc__unset-button-styles px-10 flex dc__bg-n0--opacity-0_2 pointer"
456466
onClick={handleToggleOpenAllStages}
457467
aria-label="Expand all stages"
468+
data-toggle-state={areAllStagesExpanded}
458469
>
459470
{areAllStagesExpanded ? (
460471
<ICCollapseAll className="icon-dim-16 dc__no-shrink dc__transition--transform scn-0" />
@@ -522,4 +533,4 @@ export const LogsRenderer = ({
522533
: renderLogs()
523534
}
524535

525-
export default LogsRenderer
536+
export default withShortcut(LogsRenderer)

src/Shared/Components/CICDHistory/TriggerOutput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ import { getTagDetails, getTriggerDetails, cancelCiTrigger, cancelPrePostCdTrigg
6464
import { DEFAULT_ENV, TIMEOUT_VALUE, WORKER_POD_BASE_URL } from './constants'
6565
import { GitTriggers } from '../../types'
6666
import warn from '../../../Assets/Icon/ic-warning.svg'
67-
import { LogsRenderer } from './LogsRenderer'
67+
import LogsRenderer from './LogsRenderer'
6868
import DeploymentDetailSteps from './DeploymentDetailSteps'
6969
import { DeploymentHistoryDetailedView, DeploymentHistoryConfigList } from './DeploymentHistoryDiff'
7070
import { GitChanges, Scroller } from './History.components'

src/Shared/Components/CICDHistory/cicdHistory.scss

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,6 @@
3737
position: absolute;
3838
bottom: 12px;
3939
right: 12px;
40-
transition: top 0.3s;
41-
padding: 6px;
42-
width: 32px;
43-
height: 32px;
44-
border-radius: 4px;
45-
box-shadow:
46-
0 0 4px 0 rgba(0, 10, 20, 0.5),
47-
0 0 4px 0 rgba(0, 10, 20, 0.5);
48-
background-color: #2c3354;
49-
opacity: 0.8;
50-
51-
&:hover {
52-
opacity: 1;
53-
}
5440
}
5541

5642
.ci-details__history {
@@ -110,10 +96,6 @@
11096
transition: height 0.3s;
11197
}
11298
}
113-
114-
.zoom {
115-
transition: top 0.3s;
116-
}
11799
}
118100
}
119101

@@ -294,3 +276,30 @@
294276
width: min(100%, 800px);
295277
}
296278
}
279+
280+
.log-resize-button {
281+
transition: opacity 0.2s ease-in-out;
282+
padding: 6px;
283+
width: 32px;
284+
height: 32px;
285+
border-radius: 4px;
286+
box-shadow:
287+
0 0 4px 0 rgba(0, 10, 20, 0.5),
288+
0 0 4px 0 rgba(0, 10, 20, 0.5);
289+
background-color: #2c3354;
290+
opacity: 0.8;
291+
z-index: 11;
292+
293+
& > svg {
294+
transition: transform 0.2s ease-in-out;
295+
transform: scale(1);
296+
}
297+
298+
&:hover {
299+
opacity: 1;
300+
301+
& > svg {
302+
transform: scale(1.1);
303+
}
304+
}
305+
}

src/Shared/Components/CICDHistory/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export * from './service'
2626
export * from './History.components'
2727
export * from './utils'
2828
export * from './TriggerOutput'
29-
export * from './LogsRenderer'
29+
export { default as LogsRenderer } from './LogsRenderer'
3030
export * from './DeploymentHistoryDiff'
3131
export * from './CiPipelineSourceConfig'
3232
export * from './StatusFilterButtonComponent'

0 commit comments

Comments
 (0)