mirror of
https://github.com/harness/drone.git
synced 2025-05-12 06:59:54 +08:00
feat: [CDE-626]: Replaced the log polling api with stream api to fetch realtime logs (#3631)
* fix: UI changes for the button scroll and alignment fix * fix: fixed lint issuews * feat: Replaced the log polling api with stream api to fetch realtime logs
This commit is contained in:
parent
30197968cc
commit
aff47081e7
@ -13,6 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
@import 'src/utils/utils';
|
||||||
|
|
||||||
.customSubheader {
|
.customSubheader {
|
||||||
height: 10vh;
|
height: 10vh;
|
||||||
@ -111,3 +112,45 @@
|
|||||||
width: 130px;
|
width: 130px;
|
||||||
justify-content: space-between !important;
|
justify-content: space-between !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scrollDownBtn {
|
||||||
|
position: absolute;
|
||||||
|
padding: 8px !important;
|
||||||
|
bottom: 35px;
|
||||||
|
right: 30px;
|
||||||
|
|
||||||
|
& > :global(.bp3-icon) {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :global(.bp3-button-text) {
|
||||||
|
width: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover > :global(.bp3-button-text) {
|
||||||
|
width: auto;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.consoleContainer {
|
||||||
|
min-height: 120px !important;
|
||||||
|
max-height: 70vh !important;
|
||||||
|
overflow: scroll;
|
||||||
|
align-items: start !important;
|
||||||
|
padding-top: var(--spacing-large) !important;
|
||||||
|
padding-bottom: var(--spacing-large) !important;
|
||||||
|
padding-left: var(--spacing-xlarge) !important;
|
||||||
|
background-color: var(--black) !important;
|
||||||
|
color: var(--white) !important;
|
||||||
|
pre {
|
||||||
|
background-color: var(--black) !important;
|
||||||
|
color: var(--white) !important;
|
||||||
|
text-align: start !important;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: var(--font-family-mono) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
// This is an auto-generated file
|
// This is an auto-generated file
|
||||||
export declare const accordionnCustomSummary: string
|
export declare const accordionnCustomSummary: string
|
||||||
export declare const cardContainer: string
|
export declare const cardContainer: string
|
||||||
|
export declare const consoleContainer: string
|
||||||
export declare const containerlogsTitle: string
|
export declare const containerlogsTitle: string
|
||||||
export declare const copyBtn: string
|
export declare const copyBtn: string
|
||||||
export declare const customSubheader: string
|
export declare const customSubheader: string
|
||||||
@ -25,4 +26,5 @@ export declare const gitspaceIcon: string
|
|||||||
export declare const gitspaceIdContainer: string
|
export declare const gitspaceIdContainer: string
|
||||||
export declare const pageMain: string
|
export declare const pageMain: string
|
||||||
export declare const popover: string
|
export declare const popover: string
|
||||||
|
export declare const scrollDownBtn: string
|
||||||
export declare const titleContainer: string
|
export declare const titleContainer: string
|
||||||
|
@ -26,7 +26,8 @@ import {
|
|||||||
Page,
|
Page,
|
||||||
Text,
|
Text,
|
||||||
useToaster,
|
useToaster,
|
||||||
AccordionHandle
|
AccordionHandle,
|
||||||
|
ButtonSize
|
||||||
} from '@harnessio/uicore'
|
} from '@harnessio/uicore'
|
||||||
import { Play } from 'iconoir-react'
|
import { Play } from 'iconoir-react'
|
||||||
import { useHistory, useParams } from 'react-router-dom'
|
import { useHistory, useParams } from 'react-router-dom'
|
||||||
@ -53,12 +54,10 @@ import { useGitspaceDetails } from 'cde-gitness/hooks/useGitspaceDetails'
|
|||||||
import { useGitspaceEvents } from 'cde-gitness/hooks/useGitspaceEvents'
|
import { useGitspaceEvents } from 'cde-gitness/hooks/useGitspaceEvents'
|
||||||
import { useGitspaceActions } from 'cde-gitness/hooks/useGitspaceActions'
|
import { useGitspaceActions } from 'cde-gitness/hooks/useGitspaceActions'
|
||||||
import { useDeleteGitspaces } from 'cde-gitness/hooks/useDeleteGitspaces'
|
import { useDeleteGitspaces } from 'cde-gitness/hooks/useDeleteGitspaces'
|
||||||
import { useGitspacesLogs } from 'cde-gitness/hooks/useGitspaceLogs'
|
|
||||||
import { useOpenVSCodeBrowserURL } from 'cde-gitness/hooks/useOpenVSCodeBrowserURL'
|
import { useOpenVSCodeBrowserURL } from 'cde-gitness/hooks/useOpenVSCodeBrowserURL'
|
||||||
import { ErrorCard } from 'cde-gitness/components/ErrorCard/ErrorCard'
|
import { ErrorCard } from 'cde-gitness/components/ErrorCard/ErrorCard'
|
||||||
import CopyButton from 'cde-gitness/components/CopyButton/CopyButton'
|
import CopyButton from 'cde-gitness/components/CopyButton/CopyButton'
|
||||||
import ContainerLogs from '../../components/ContainerLogs/ContainerLogs'
|
import Logger from './Logger/Logger'
|
||||||
import { useGetLogStream } from '../../hooks/useGetLogStream'
|
|
||||||
import css from './GitspaceDetails.module.scss'
|
import css from './GitspaceDetails.module.scss'
|
||||||
|
|
||||||
const GitspaceDetails = () => {
|
const GitspaceDetails = () => {
|
||||||
@ -67,11 +66,15 @@ const GitspaceDetails = () => {
|
|||||||
const { routes, standalone } = useAppContext()
|
const { routes, standalone } = useAppContext()
|
||||||
const { showError, showSuccess } = useToaster()
|
const { showError, showSuccess } = useToaster()
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
|
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||||
const [startTriggred, setStartTriggred] = useState<boolean>(false)
|
const [startTriggred, setStartTriggred] = useState<boolean>(false)
|
||||||
const [triggerPollingOnStart, setTriggerPollingOnStart] = useState<EnumGitspaceStateType>()
|
const [triggerPollingOnStart, setTriggerPollingOnStart] = useState<EnumGitspaceStateType>()
|
||||||
const { gitspaceId = '' } = useParams<{ gitspaceId?: string }>()
|
const { gitspaceId = '' } = useParams<{ gitspaceId?: string }>()
|
||||||
|
|
||||||
|
const logCardId = 'logsCard'
|
||||||
|
const [expandedTab, setExpandedTab] = useState('')
|
||||||
const [isStreamingLogs, setIsStreamingLogs] = useState(false)
|
const [isStreamingLogs, setIsStreamingLogs] = useState(false)
|
||||||
|
const [isBottom, setIsBottom] = useState(false)
|
||||||
|
|
||||||
const [startPolling, setStartPolling] = useState<GitspaceActionType | undefined>(undefined)
|
const [startPolling, setStartPolling] = useState<GitspaceActionType | undefined>(undefined)
|
||||||
|
|
||||||
@ -79,14 +82,6 @@ const GitspaceDetails = () => {
|
|||||||
|
|
||||||
const { data: eventData, refetch: refetchEventData } = useGitspaceEvents({ gitspaceId })
|
const { data: eventData, refetch: refetchEventData } = useGitspaceEvents({ gitspaceId })
|
||||||
|
|
||||||
const {
|
|
||||||
data: responseData,
|
|
||||||
refetch: refetchLogsData,
|
|
||||||
response,
|
|
||||||
error: streamLogsError,
|
|
||||||
loading: logsLoading
|
|
||||||
} = useGitspacesLogs({ gitspaceId })
|
|
||||||
|
|
||||||
const { mutate: actionMutate, loading: mutateLoading } = useGitspaceActions({ gitspaceId })
|
const { mutate: actionMutate, loading: mutateLoading } = useGitspaceActions({ gitspaceId })
|
||||||
|
|
||||||
const { mutate: deleteGitspace, loading: deleteLoading } = useDeleteGitspaces({ gitspaceId })
|
const { mutate: deleteGitspace, loading: deleteLoading } = useDeleteGitspaces({ gitspaceId })
|
||||||
@ -111,15 +106,13 @@ const GitspaceDetails = () => {
|
|||||||
defaultTo(item?.timestamp, 0) >= defaultTo(data?.instance?.updated, 0)
|
defaultTo(item?.timestamp, 0) >= defaultTo(data?.instance?.updated, 0)
|
||||||
)
|
)
|
||||||
if (disabledActionButtons && filteredEvent?.length && !isStreamingLogs) {
|
if (disabledActionButtons && filteredEvent?.length && !isStreamingLogs) {
|
||||||
refetchLogsData()
|
|
||||||
setIsStreamingLogs(true)
|
setIsStreamingLogs(true)
|
||||||
} else if (
|
viewLogs()
|
||||||
(filteredEvent?.length && !disabledActionButtons && isStreamingLogs) ||
|
} else if (filteredEvent?.length && !disabledActionButtons && isStreamingLogs) {
|
||||||
(isStreamingLogs && streamLogsError)
|
|
||||||
) {
|
|
||||||
setIsStreamingLogs(false)
|
setIsStreamingLogs(false)
|
||||||
|
viewLogs()
|
||||||
}
|
}
|
||||||
}, [eventData, data?.instance?.updated, disabledActionButtons, streamLogsError])
|
}, [eventData, data?.instance?.updated, disabledActionButtons])
|
||||||
|
|
||||||
usePolling(
|
usePolling(
|
||||||
async () => {
|
async () => {
|
||||||
@ -135,19 +128,6 @@ const GitspaceDetails = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
usePolling(
|
|
||||||
async () => {
|
|
||||||
if (!standalone) {
|
|
||||||
await refetchLogsData()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pollingInterval: 10000,
|
|
||||||
startCondition: (eventData?.[eventData?.length - 1]?.event as string) === 'agent_gitspace_creation_start',
|
|
||||||
stopCondition: pollingCondition
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const startTrigger = async () => {
|
const startTrigger = async () => {
|
||||||
if (redirectFrom && !startTriggred && !mutateLoading) {
|
if (redirectFrom && !startTriggred && !mutateLoading) {
|
||||||
@ -171,8 +151,6 @@ const GitspaceDetails = () => {
|
|||||||
}
|
}
|
||||||
}, [data?.state, redirectFrom, mutateLoading, startTriggred])
|
}, [data?.state, redirectFrom, mutateLoading, startTriggred])
|
||||||
|
|
||||||
const formattedlogsdata = useGetLogStream(standalone ? { response } : { response: undefined })
|
|
||||||
|
|
||||||
const confirmDelete = useConfirmAct()
|
const confirmDelete = useConfirmAct()
|
||||||
|
|
||||||
const handleDelete = async (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
const handleDelete = async (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||||
@ -203,14 +181,6 @@ const GitspaceDetails = () => {
|
|||||||
const myRef = useRef<any | null>(null)
|
const myRef = useRef<any | null>(null)
|
||||||
const selectedIde = getIDEOption(data?.ide, getString)
|
const selectedIde = getIDEOption(data?.ide, getString)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (standalone ? formattedlogsdata.data : responseData) {
|
|
||||||
accordionRef.current?.open('logsCard')
|
|
||||||
} else {
|
|
||||||
accordionRef.current?.close('logsCard')
|
|
||||||
}
|
|
||||||
}, [standalone, responseData, formattedlogsdata.data])
|
|
||||||
|
|
||||||
const triggerGitspace = async () => {
|
const triggerGitspace = async () => {
|
||||||
try {
|
try {
|
||||||
setStartPolling(GitspaceActionType.START)
|
setStartPolling(GitspaceActionType.START)
|
||||||
@ -227,6 +197,19 @@ const GitspaceDetails = () => {
|
|||||||
const viewLogs = () => {
|
const viewLogs = () => {
|
||||||
myRef.current?.scrollIntoView()
|
myRef.current?.scrollIntoView()
|
||||||
accordionRef.current?.open('logsCard')
|
accordionRef.current?.open('logsCard')
|
||||||
|
setExpandedTab('logsCard')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
const logContainer = containerRef.current as HTMLDivElement
|
||||||
|
const scrollParent = logContainer?.parentElement as HTMLDivElement
|
||||||
|
if (!isBottom) {
|
||||||
|
scrollParent.scrollTop = scrollParent.scrollHeight
|
||||||
|
setIsBottom(true)
|
||||||
|
} else if (isBottom) {
|
||||||
|
scrollParent.scrollTop = 0
|
||||||
|
setIsBottom(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -451,16 +434,20 @@ const GitspaceDetails = () => {
|
|||||||
<Card className={css.cardContainer}>
|
<Card className={css.cardContainer}>
|
||||||
<EventTimelineAccordion data={eventData as TypesGitspaceEventResponse[]} />
|
<EventTimelineAccordion data={eventData as TypesGitspaceEventResponse[]} />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className={css.cardContainer}>
|
<Card className={css.cardContainer}>
|
||||||
<Container ref={myRef}>
|
<Container ref={myRef}>
|
||||||
<Accordion activeId={''} ref={accordionRef}>
|
<Accordion
|
||||||
|
activeId={expandedTab}
|
||||||
|
ref={accordionRef}
|
||||||
|
onChange={(e: string) => {
|
||||||
|
setExpandedTab(e)
|
||||||
|
}}>
|
||||||
<Accordion.Panel
|
<Accordion.Panel
|
||||||
className={css.accordionnCustomSummary}
|
className={css.accordionnCustomSummary}
|
||||||
summary={
|
summary={
|
||||||
<Layout.Vertical spacing="small">
|
<Layout.Vertical spacing="small">
|
||||||
<Text
|
<Text
|
||||||
rightIcon={isStreamingLogs || logsLoading ? 'steps-spinner' : undefined}
|
rightIcon={isStreamingLogs ? 'steps-spinner' : undefined}
|
||||||
className={css.containerlogsTitle}
|
className={css.containerlogsTitle}
|
||||||
font={{ variation: FontVariation.CARD_TITLE }}
|
font={{ variation: FontVariation.CARD_TITLE }}
|
||||||
margin={{ left: 'large' }}>
|
margin={{ left: 'large' }}>
|
||||||
@ -469,10 +456,27 @@ const GitspaceDetails = () => {
|
|||||||
<Text margin={{ left: 'large' }}>{getString('cde.details.containerLogsSubText')} </Text>
|
<Text margin={{ left: 'large' }}>{getString('cde.details.containerLogsSubText')} </Text>
|
||||||
</Layout.Vertical>
|
</Layout.Vertical>
|
||||||
}
|
}
|
||||||
id="logsCard"
|
id={logCardId}
|
||||||
details={
|
details={
|
||||||
<Container width="100%">
|
<Container width="100%" className={css.consoleContainer}>
|
||||||
<ContainerLogs data={standalone ? formattedlogsdata.data : responseData} />
|
<Logger
|
||||||
|
value={data?.name ?? ''}
|
||||||
|
state={data?.state ?? ''}
|
||||||
|
logKey={data?.log_key ?? ''}
|
||||||
|
isStreaming={isStreamingLogs}
|
||||||
|
expanded={true}
|
||||||
|
localRef={containerRef}
|
||||||
|
setIsBottom={setIsBottom}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size={ButtonSize.SMALL}
|
||||||
|
variation={ButtonVariation.PRIMARY}
|
||||||
|
text={isBottom ? getString('top') : getString('bottom')}
|
||||||
|
icon={isBottom ? 'arrow-up' : 'arrow-down'}
|
||||||
|
iconProps={{ size: 10 }}
|
||||||
|
onClick={handleClick}
|
||||||
|
className={css.scrollDownBtn}
|
||||||
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { useAppContext } from 'AppContext'
|
||||||
|
|
||||||
|
const LogStreaming: React.FC<any> = ({ logKeyList, onMessageStreaming, onError }: any) => {
|
||||||
|
const { hooks } = useAppContext()
|
||||||
|
const { subscribe, closeStream } = hooks?.useLogsStreaming(logKeyList, onMessageStreaming, onError)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribe()
|
||||||
|
|
||||||
|
return () => closeStream()
|
||||||
|
}, [])
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogStreaming
|
@ -0,0 +1,106 @@
|
|||||||
|
@import 'src/utils/utils';
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.line {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
cursor: text;
|
||||||
|
min-height: 20px;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
@include mono-font;
|
||||||
|
color: var(--white);
|
||||||
|
|
||||||
|
word-wrap: break-word !important;
|
||||||
|
white-space: pre-wrap !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipelineSteps {
|
||||||
|
padding: 10px 20px 0 !important;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: 10px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--black);
|
||||||
|
position: absolute;
|
||||||
|
top: 64px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 34px;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 10px 0 6px;
|
||||||
|
position: sticky;
|
||||||
|
top: 74px;
|
||||||
|
z-index: 2;
|
||||||
|
background-color: var(--black);
|
||||||
|
|
||||||
|
&.expanded {
|
||||||
|
.chevron {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron {
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #22222aa9;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: #22222a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected .name {
|
||||||
|
color: var(--primary-7) !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: #b0b1c3 !important;
|
||||||
|
font-weight: 400 !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-family: var(--font-family-mono);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepLogContainer {
|
||||||
|
padding: 15px 10px 15px 36px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.consoleLine {
|
||||||
|
color: var(--white);
|
||||||
|
|
||||||
|
@include mono-font;
|
||||||
|
|
||||||
|
word-wrap: break-word !important;
|
||||||
|
white-space: pre-wrap !important;
|
||||||
|
cursor: text;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:empty {
|
||||||
|
display: inline-block;
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
web/src/cde-gitness/pages/GitspaceDetails/Logger/Logger.module.scss.d.ts
vendored
Normal file
29
web/src/cde-gitness/pages/GitspaceDetails/Logger/Logger.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Harness, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
// This is an auto-generated file
|
||||||
|
export declare const chevron: string
|
||||||
|
export declare const consoleLine: string
|
||||||
|
export declare const expanded: string
|
||||||
|
export declare const line: string
|
||||||
|
export declare const main: string
|
||||||
|
export declare const name: string
|
||||||
|
export declare const pipelineSteps: string
|
||||||
|
export declare const selected: string
|
||||||
|
export declare const stepContainer: string
|
||||||
|
export declare const stepHeader: string
|
||||||
|
export declare const stepLogContainer: string
|
104
web/src/cde-gitness/pages/GitspaceDetails/Logger/Logger.tsx
Normal file
104
web/src/cde-gitness/pages/GitspaceDetails/Logger/Logger.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
|
import { Container } from '@harnessio/uicore'
|
||||||
|
import cx from 'classnames'
|
||||||
|
import { GitspaceStatus } from 'cde-gitness/constants'
|
||||||
|
import { lineElement } from 'components/LogViewer/LogViewer'
|
||||||
|
import { useScheduleJob } from 'hooks/useScheduleJob'
|
||||||
|
import { useAppContext } from 'AppContext'
|
||||||
|
import LogStreaming from './LogStreaming'
|
||||||
|
import css from './Logger.module.scss'
|
||||||
|
|
||||||
|
interface LoggerProps {
|
||||||
|
stepNameLogKeyMap?: Map<string, string>
|
||||||
|
expanded?: boolean
|
||||||
|
logKey: string
|
||||||
|
state: string
|
||||||
|
value: string
|
||||||
|
isStreaming: boolean
|
||||||
|
localRef: any
|
||||||
|
setIsBottom: (val: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Logger: React.FC<LoggerProps> = ({ expanded, logKey, value, state, isStreaming, localRef, setIsBottom }) => {
|
||||||
|
const logKeyList: string[] = [logKey]
|
||||||
|
const { hooks } = useAppContext()
|
||||||
|
const [startStreaming, setStartStreaming] = useState(false)
|
||||||
|
const { getBlobData, blobDataCur } = hooks?.useLogsContent(logKeyList)
|
||||||
|
|
||||||
|
const sendStreamLogToRenderer = useScheduleJob({
|
||||||
|
handler: useCallback((blocks: string[]) => {
|
||||||
|
const logContainer = localRef.current as HTMLDivElement
|
||||||
|
|
||||||
|
if (logContainer) {
|
||||||
|
const fragment = new DocumentFragment()
|
||||||
|
|
||||||
|
blocks.forEach((block: string) => {
|
||||||
|
const blockData = JSON.parse(block)
|
||||||
|
const linePos = blockData.pos + 1
|
||||||
|
const localDate = new Date(blockData.time)
|
||||||
|
const formattedDate = localDate.toLocaleString()
|
||||||
|
|
||||||
|
fragment.appendChild(
|
||||||
|
lineElement(`${linePos} ${blockData.level} ${formattedDate.replace(',', '')} ${blockData.out}`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
logContainer?.appendChild(fragment)
|
||||||
|
|
||||||
|
const scrollParent = logContainer?.parentElement as HTMLDivElement
|
||||||
|
scrollParent.scrollTop = scrollParent?.scrollHeight
|
||||||
|
setIsBottom(true)
|
||||||
|
}
|
||||||
|
}, []),
|
||||||
|
isStreaming: true
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const onMessageStreaming = (e: any) => {
|
||||||
|
if (e.data) {
|
||||||
|
sendStreamLogToRenderer(e.data || '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onError = (e: any) => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLogData = async () => {
|
||||||
|
await getBlobData(logKeyList)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (expanded && (state === GitspaceStatus.RUNNING || state === GitspaceStatus.STOPPED)) {
|
||||||
|
// Fetch from blob
|
||||||
|
getLogData()
|
||||||
|
} else if (expanded && state !== GitspaceStatus.RUNNING && state !== GitspaceStatus.STOPPED) {
|
||||||
|
if (isStreaming) {
|
||||||
|
setStartStreaming(true)
|
||||||
|
} else {
|
||||||
|
setStartStreaming(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [state, isStreaming, expanded])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (blobDataCur && (state === GitspaceStatus.RUNNING || state === GitspaceStatus.STOPPED)) {
|
||||||
|
const logData = JSON.parse(blobDataCur)?.map((logs: { level: string; time: string }) => {
|
||||||
|
return JSON.stringify(logs)
|
||||||
|
})
|
||||||
|
sendStreamLogToRenderer(logData || '')
|
||||||
|
}
|
||||||
|
}, [blobDataCur])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{startStreaming ? (
|
||||||
|
<LogStreaming logKeyList={logKeyList} onMessageStreaming={onMessageStreaming} onError={onError} />
|
||||||
|
) : null}
|
||||||
|
<Container key={`harnesslog_${value}`} ref={localRef} className={cx(css.main, css.stepLogContainer)} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Logger
|
@ -1034,6 +1034,7 @@ export interface TypesGitspaceConfig {
|
|||||||
state?: EnumGitspaceStateType
|
state?: EnumGitspaceStateType
|
||||||
updated?: number
|
updated?: number
|
||||||
user_id?: string
|
user_id?: string
|
||||||
|
log_key?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TypesGitspaceEventResponse {
|
export interface TypesGitspaceEventResponse {
|
||||||
|
Loading…
Reference in New Issue
Block a user