This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 17084c371fd0d0523463f6b69e88b0a218134942 Author: Marat Gubaidullin <marat.gubaidul...@gmail.com> AuthorDate: Thu Jul 27 18:22:36 2023 -0400 devservices logs #817 --- .../karavan-app/src/main/webui/src/Main.tsx | 41 +++++++++++------- .../src/main/webui/src/api/ProjectService.ts | 50 +++++++++++----------- .../src/main/webui/src/api/ProjectStore.ts | 8 ---- .../main/webui/src/containers/ContainersPage.tsx | 29 ++----------- .../karavan-app/src/main/webui/src/index.css | 16 +++---- .../src/main/webui/src/project/DevModeToolbar.tsx | 19 ++++---- .../src/main/webui/src/project/ProjectPage.tsx | 19 ++++---- .../webui/src/project/dashboard/DashboardTab.tsx | 19 ++++---- .../main/webui/src/project/log/ProjectLogPanel.tsx | 14 +++--- .../webui/src/project/pipeline/ProjectStatus.tsx | 5 +-- .../src/main/webui/src/services/ServicesPage.tsx | 23 +++------- .../main/webui/src/services/ServicesTableRow.tsx | 21 +++++++-- 12 files changed, 125 insertions(+), 139 deletions(-) diff --git a/karavan-web/karavan-app/src/main/webui/src/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/Main.tsx index 8adfe79d..98ca08f1 100644 --- a/karavan-web/karavan-app/src/main/webui/src/Main.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/Main.tsx @@ -28,12 +28,13 @@ import {ContainersPage} from "./containers/ContainersPage"; import {ProjectEventBus} from "./api/ProjectEventBus"; import {AppConfig, ContainerStatus, Project, ToastMessage} from "./api/ProjectModels"; import {ProjectPage} from "./project/ProjectPage"; -import {useAppConfigStore, useDevModeStore, useFileStore, useProjectStore} from "./api/ProjectStore"; +import {useAppConfigStore, useDevModeStore, useFileStore, useProjectStore, useStatusesStore} from "./api/ProjectStore"; import {Notification} from "./Notification"; import {InfrastructureAPI} from "./designer/utils/InfrastructureAPI"; import {KnowledgebasePage} from "./knowledgebase/KnowledgebasePage"; import {ServicesPage} from "./services/ServicesPage"; import {shallow} from "zustand/shallow"; +import {ProjectService} from "./api/ProjectService"; class MenuItem { pageId: string = ''; @@ -50,12 +51,16 @@ class MenuItem { export const Main = () => { const [config, setConfig] = useAppConfigStore((state) => [state.config, state.setConfig], shallow) + const [setContainers] = useStatusesStore((state) => [state.setContainers], shallow); const [pageId, setPageId] = useState<string>('projects'); const [request, setRequest] = useState<string>(uuidv4()); const [showUser, setShowUser] = useState<boolean>(false); useEffect(() => { console.log("Main Start"); + const interval = setInterval(() => { + getStatuses(); + }, 1000); const sub = ProjectEventBus.onSelectProject()?.subscribe((project: Project | undefined) => { if (project) setPageId("project"); }); @@ -64,17 +69,15 @@ export const Main = () => { if (authType === 'oidc') { SsoApi.auth(() => { KaravanApi.getMe((user: any) => { - console.log("me", user); getData(); }); }); } - if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') { - getData(); - } + getData(); }); return () => { console.log("Main End"); + clearInterval(interval); sub?.unsubscribe(); }; }, []); @@ -88,17 +91,26 @@ export const Main = () => { } }); } + function getStatuses() { + if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') { + KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => { + setContainers(statuses); + }); + } + } function getData() { - KaravanApi.getConfiguration((config: AppConfig) => { - setRequest(uuidv4()); - setConfig(config); - useAppConfigStore.setState({config: config}); - InfrastructureAPI.infrastructure = config.infrastructure; - }); - updateKamelets(); - updateComponents(); - // updateSupportedComponents(); // not implemented yet + if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') { + KaravanApi.getConfiguration((config: AppConfig) => { + setRequest(uuidv4()); + setConfig(config); + useAppConfigStore.setState({config: config}); + InfrastructureAPI.infrastructure = config.infrastructure; + }); + updateKamelets(); + updateComponents(); + // updateSupportedComponents(); // not implemented yet + } } async function updateKamelets(): Promise<void> { @@ -165,7 +177,6 @@ export const Main = () => { onClick={event => { useFileStore.setState({operation: 'none', file: undefined}) useDevModeStore.setState({podName: undefined, status: "none"}) - useProjectStore.setState({containerStatus: new ContainerStatus({}),}) setPageId(page.pageId); }} /> diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts index cdfada6f..14f42cbb 100644 --- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts +++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts @@ -45,7 +45,7 @@ export class ProjectService { KaravanApi.manageContainer('dev', 'devmove', project.projectId, 'stop', res => { useDevModeStore.setState({status: 'none'}) if (res.status === 200) { - useLogStore.setState({showLog: false, type: 'container', isRunning: false}) + useLogStore.setState({showLog: false, type: 'container'}) } else { ProjectEventBus.sendAlert(new ToastMessage('Error stopping DevMode container', res.statusText, 'warning')) } @@ -57,7 +57,7 @@ export class ProjectService { KaravanApi.manageContainer('dev', 'devmove', project.projectId, 'pause', res => { useDevModeStore.setState({status: 'none'}) if (res.status === 200) { - useLogStore.setState({showLog: false, type: 'container', isRunning: false}) + useLogStore.setState({showLog: false, type: 'container'}) } else { ProjectEventBus.sendAlert(new ToastMessage('Error stopping DevMode container', res.statusText, 'warning')) } @@ -70,35 +70,35 @@ export class ProjectService { KaravanApi.deleteDevModeContainer(project.projectId, false, res => { useDevModeStore.setState({status: 'none'}) if (res.status === 202) { - useLogStore.setState({showLog: false, type: 'container', isRunning: false}) + useLogStore.setState({showLog: false, type: 'container'}) } else { ProjectEventBus.sendAlert(new ToastMessage('Error delete runner', res.statusText, 'warning')) } }); } - public static getDevModeStatus(project: Project) { - const projectId = project.projectId; - KaravanApi.getDevModePodStatus(projectId, res => { - if (res.status === 200) { - unstable_batchedUpdates(() => { - const containerStatus = res.data; - if (useDevModeStore.getState().podName !== containerStatus.containerName){ - useDevModeStore.setState({podName: containerStatus.containerName}) - } - if (useDevModeStore.getState().status !== 'wip'){ - useLogStore.setState({isRunning: true}) - } - useProjectStore.setState({containerStatus: containerStatus}); - }) - } else { - unstable_batchedUpdates(() => { - useDevModeStore.setState({status: 'none', podName: undefined}) - useProjectStore.setState({containerStatus: new ContainerStatus({})}); - }) - } - }); - } + // public static getDevModeStatus(project: Project) { + // const projectId = project.projectId; + // KaravanApi.getDevModePodStatus(projectId, res => { + // if (res.status === 200) { + // unstable_batchedUpdates(() => { + // const containerStatus = res.data; + // if (useDevModeStore.getState().podName !== containerStatus.containerName){ + // useDevModeStore.setState({podName: containerStatus.containerName}) + // } + // if (useDevModeStore.getState().status !== 'wip'){ + // useLogStore.setState({isRunning: true}) + // } + // useStatusesStore.setState({containerStatus: containerStatus}); + // }) + // } else { + // unstable_batchedUpdates(() => { + // useDevModeStore.setState({status: 'none', podName: undefined}) + // useStatusesStore.setState({containerStatus: new ContainerStatus({})}); + // }) + // } + // }); + // } public static pushProject(project: Project, commitMessage: string) { useProjectStore.setState({isPushing: true}) diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts index 80c99593..4c554926 100644 --- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts +++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts @@ -59,7 +59,6 @@ interface ProjectState { project: Project; isPushing: boolean, isRunning: boolean, - containerStatus: ContainerStatus, operation: "create" | "select" | "delete" | "none" | "copy"; setProject: (project: Project, operation: "create" | "select" | "delete"| "none" | "copy") => void; setOperation: (o: "create" | "select" | "delete"| "none" | "copy") => void; @@ -70,7 +69,6 @@ export const useProjectStore = create<ProjectState>((set) => ({ operation: "none", isPushing: false, isRunning: false, - containerStatus: new ContainerStatus(), setProject: (project: Project, operation: "create" | "select" | "delete"| "none" | "copy") => { set((state: ProjectState) => ({ project: project, @@ -191,7 +189,6 @@ export const useStatusesStore = create<StatusesState>((set) => ({ interface LogState { podName?: string, - isRunning: boolean, data: string; setData: (data: string) => void; addData: (data: string) => void; @@ -202,13 +199,11 @@ interface LogState { setShowLog: (showLog: boolean) => void; type: 'container' | 'pipeline' | 'none', setType: (type: 'container' | 'pipeline' | 'none') => void, - setIsRunning: (isRunning: boolean) => void; } export const useLogStore = create<LogState>((set) => ({ podName: undefined, data: '', - isRunning: false, setData: (data: string) => { set({data: data}) }, @@ -232,9 +227,6 @@ export const useLogStore = create<LogState>((set) => ({ setShowLog: (showLog: boolean) => { set(() => ({showLog: showLog})); }, - setIsRunning: (isRunning: boolean) => { - set(() => ({isRunning: isRunning})); - }, type: "none", setType: (type: 'container' | 'pipeline' | 'none') => { set((state: LogState) => ({type: type})); diff --git a/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx b/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx index 08539413..a2ae7686 100644 --- a/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/containers/ContainersPage.tsx @@ -1,7 +1,7 @@ -import React, {useEffect, useState} from 'react'; +import React, {useState} from 'react'; import { Bullseye, - Button, EmptyState, EmptyStateIcon, EmptyStateVariant, + EmptyState, EmptyStateIcon, EmptyStateVariant, PageSection, Spinner, Text, TextContent, @@ -13,8 +13,6 @@ import { import '../designer/karavan.css'; import {ContainerStatus} from "../api/ProjectModels"; import {TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table"; -import {KaravanApi} from "../api/KaravanApi"; -import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon"; import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon"; import {MainToolbar} from "../designer/MainToolbar"; import {useAppConfigStore, useStatusesStore} from "../api/ProjectStore"; @@ -24,27 +22,11 @@ import {ContainerTableRow} from "./ContainerTableRow"; export const ContainersPage = () => { const [config] = useAppConfigStore((state) => [state.config], shallow) - const [containers, setContainers] = useStatusesStore((state) => [state.containers, state.setContainers], shallow); + const [containers] = useStatusesStore((state) => [state.containers, state.setContainers], shallow); const [filter, setFilter] = useState<string>(''); - const [loading, setLoading] = useState<boolean>(true); + const [loading] = useState<boolean>(true); const [selectedEnv, setSelectedEnv] = useState<string[]>([config.environment]); - useEffect(() => { - const interval = setInterval(() => { - updateContainerStatuses() - }, 700); - return () => { - clearInterval(interval) - }; - }, []); - - function updateContainerStatuses() { - KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => { - setContainers(statuses); - setLoading(false); - }); - } - function selectEnvironment(name: string, selected: boolean) { if (selected && !selectedEnv.includes(name)) { setSelectedEnv((state: string[]) => { @@ -61,9 +43,6 @@ export const ContainersPage = () => { function tools() { return (<Toolbar id="toolbar-group-types"> <ToolbarContent> - <ToolbarItem> - <Button variant="link" icon={<RefreshIcon/>} onClick={e => updateContainerStatuses()}/> - </ToolbarItem> <ToolbarItem> <ToggleGroup aria-label="Default with single selectable"> {config.environments.map(env => ( diff --git a/karavan-web/karavan-app/src/main/webui/src/index.css b/karavan-web/karavan-app/src/main/webui/src/index.css index 54dbc583..0367351c 100644 --- a/karavan-web/karavan-app/src/main/webui/src/index.css +++ b/karavan-web/karavan-app/src/main/webui/src/index.css @@ -180,7 +180,7 @@ margin-bottom: 100px; } -.karavan .project-page .project-log { +.karavan .project-log { position: absolute; bottom: 0; right: 0; @@ -191,7 +191,7 @@ align-items: stretch; } -.karavan .project-page .project-log .buttons { +.karavan .project-log .buttons { display: flex; flex-direction: row; justify-content: flex-end; @@ -199,26 +199,26 @@ padding-right: 6px; } -.karavan .project-page .project-log .buttons button, -.karavan .project-page .project-log .buttons .pf-c-check { +.karavan .project-log .buttons button, +.karavan .project-log .buttons .pf-c-check { padding: 8px; } -.karavan .project-page .project-log .buttons .pf-c-check .pf-c-check__label{ +.karavan .project-log .buttons .pf-c-check .pf-c-check__label{ font-size: 12px; line-height: 20px; padding: 0; } -.karavan .project-page .project-log .pf-c-log-viewer__scroll-container { +.karavan .project-log .pf-c-log-viewer__scroll-container { /*height: 100% !important;*/ } -.karavan .project-page .project-log .pf-c-log-viewer__text { +.karavan .project-log .pf-c-log-viewer__text { font-size: 12px; } -.karavan .project-page .project-log .log-name { +.karavan .project-log .log-name { --pf-c-label__content--before--BorderWidth: 0; --pf-c-label--BackgroundColor: transparent; margin-right: auto; diff --git a/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx index 9777019b..9401aeb0 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx @@ -4,8 +4,7 @@ import '../designer/karavan.css'; import RocketIcon from "@patternfly/react-icons/dist/esm/icons/rocket-icon"; import ReloadIcon from "@patternfly/react-icons/dist/esm/icons/bolt-icon"; import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon"; -import PauseIcon from "@patternfly/react-icons/dist/esm/icons/pause-icon"; -import {useDevModeStore, useLogStore, useProjectStore} from "../api/ProjectStore"; +import {useDevModeStore, useLogStore, useProjectStore, useStatusesStore} from "../api/ProjectStore"; import {ProjectService} from "../api/ProjectService"; import {shallow} from "zustand/shallow"; import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon"; @@ -20,23 +19,25 @@ interface Props { export const DevModeToolbar = (props: Props) => { const [status] = useDevModeStore((state) => [state.status], shallow) - const [project, containerStatus ] = useProjectStore((state) => [state.project, state.containerStatus], shallow) + const [project ] = useProjectStore((state) => [state.project], shallow) + const [containers] = useStatusesStore((state) => [state.containers], shallow); const [verbose, setVerbose] = useState(false); - const commands = containerStatus.commands; - const isRunning = containerStatus.state === 'running'; - const inTransit = containerStatus.inTransit; + const containerStatus = containers.filter(c => c.containerName === project.projectId).at(0); + const commands = containerStatus?.commands || ['run']; + const isRunning = containerStatus?.state === 'running'; + const inTransit = containerStatus?.inTransit; const isLoading= status === 'wip'; - const color = containerStatus.state === 'running' ? "green" : "grey"; + const color = containerStatus?.state === 'running' ? "green" : "grey"; const icon = isRunning ? <UpIcon/> : <DownIcon/>; return (<Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}> <FlexItem> {(inTransit || isLoading) && <Spinner isSVG size="lg" aria-label="spinner"/>} </FlexItem> - {containerStatus.containerId && <FlexItem> + {containerStatus?.containerId && <FlexItem> <Label icon={icon} color={color}> <Tooltip content={"Show log"} position={TooltipPosition.bottom}> - <Button variant="link" + <Button variant="link" isDisabled={!isRunning} onClick={e => useLogStore.setState({showLog: true, type: 'container', podName: containerStatus.containerName})}> {containerStatus.containerName} diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx index cab863b6..976123ef 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx @@ -13,7 +13,6 @@ import {MainToolbar} from "../designer/MainToolbar"; import {ProjectTitle} from "./ProjectTitle"; import {ProjectPanel} from "./ProjectPanel"; import {FileEditor} from "./file/FileEditor"; -import {ProjectService} from "../api/ProjectService"; import {shallow} from "zustand/shallow"; export const ProjectPage = () => { @@ -23,15 +22,15 @@ export const ProjectPage = () => { const [key, setKey] = useState<string>(''); const [project] = useProjectStore((state) => [state.project], shallow ) - useEffect(() => { - // TODO: make status request only when started or just opened - const interval = setInterval(() => { - ProjectService.getDevModeStatus(project); - }, 1000); - return () => { - clearInterval(interval) - }; - }, []); + // useEffect(() => { + // // TODO: make status request only when started or just opened + // const interval = setInterval(() => { + // ProjectService.getDevModeStatus(project); + // }, 1000); + // return () => { + // clearInterval(interval) + // }; + // }, []); function post (file: ProjectFile) { KaravanApi.postProjectFile(file, res => { diff --git a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx index 9aa0a0f8..beceb5c8 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx @@ -24,11 +24,14 @@ import {InfoContainer} from "./InfoContainer"; import {InfoContext} from "./InfoContext"; import {InfoMemory} from "./InfoMemory"; import {KaravanApi} from "../../api/KaravanApi"; -import {useProjectStore} from "../../api/ProjectStore"; +import {useProjectStore, useStatusesStore} from "../../api/ProjectStore"; +import {shallow} from "zustand/shallow"; +import {ContainerStatus} from "../../api/ProjectModels"; export const DashboardTab = () => { - const {project, containerStatus} = useProjectStore(); + const [project] = useProjectStore((state) => [state.project], shallow); + const [containers] = useStatusesStore((state) => [state.containers], shallow); const [memory, setMemory] = useState({}); const [jvm, setJvm] = useState({}); const [context, setContext] = useState({}); @@ -67,10 +70,8 @@ export const DashboardTab = () => { }) } - function showConsole(): boolean { - return containerStatus.lifeCycle === 'ready'; - } - + const containerStatus = containers.filter(c => c.containerName === project.projectId).at(0); + const showConsole = containerStatus?.state === 'running' return ( <PageSection className="project-tab-panel" padding={{default: "padding"}}> <Card className="project-development"> @@ -78,15 +79,15 @@ export const DashboardTab = () => { <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentSpaceBetween"}}> <FlexItem flex={{default: "flex_1"}}> - <InfoContainer containerStatus={containerStatus}/> + <InfoContainer containerStatus={containerStatus || new ContainerStatus()}/> </FlexItem> <Divider orientation={{default: "vertical"}}/> <FlexItem flex={{default: "flex_1"}}> - <InfoMemory jvm={jvm} memory={memory} showConsole={showConsole()}/> + <InfoMemory jvm={jvm} memory={memory} showConsole={showConsole}/> </FlexItem> <Divider orientation={{default: "vertical"}}/> <FlexItem flex={{default: "flex_1"}}> - <InfoContext context={context} showConsole={showConsole()}/> + <InfoContext context={context} showConsole={showConsole}/> </FlexItem> </Flex> </CardBody> diff --git a/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx index 619b1ff7..d02ee9ac 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx @@ -5,7 +5,7 @@ import CloseIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; import ExpandIcon from '@patternfly/react-icons/dist/esm/icons/expand-icon'; import CollapseIcon from '@patternfly/react-icons/dist/esm/icons/compress-icon'; import CleanIcon from '@patternfly/react-icons/dist/esm/icons/trash-alt-icon'; -import {useLogStore} from "../../api/ProjectStore"; +import {useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; import {KaravanApi} from "../../api/KaravanApi"; import {shallow} from "zustand/shallow"; import {ProjectEventBus} from "../../api/ProjectEventBus"; @@ -14,9 +14,10 @@ import {ProjectLog} from "./ProjectLog"; const INITIAL_LOG_HEIGHT = "50%"; export const ProjectLogPanel = () => { - const [showLog, type, setShowLog, podName, isRunning] = useLogStore( - (state) => [state.showLog, state.type, state.setShowLog, state.podName, state.isRunning], shallow) + const [showLog, type, setShowLog, podName] = useLogStore( + (state) => [state.showLog, state.type, state.setShowLog, state.podName], shallow) + const [containers] = useStatusesStore((state) => [state.containers], shallow); const [height, setHeight] = useState(INITIAL_LOG_HEIGHT); const [isTextWrapped, setIsTextWrapped] = useState(true); const [autoScroll, setAutoScroll] = useState(true); @@ -24,9 +25,10 @@ export const ProjectLogPanel = () => { const [currentPodName, setCurrentPodName] = useState<string | undefined>(undefined); useEffect(() => { - console.log("ProjectLogPanel", showLog, type, podName, isRunning); + const containerStatus = containers.filter(c => c.containerName === podName).at(0); + console.log("ProjectLogPanel", showLog, type, podName, containerStatus); const controller = new AbortController(); - if (showLog && type !== 'none' && podName !== undefined && isRunning) { + if (showLog && type !== 'none' && podName !== undefined) { const f = KaravanApi.fetchData(type, podName, controller).then(value => { console.log("Fetch Started for: " + podName) }); @@ -37,7 +39,7 @@ export const ProjectLogPanel = () => { console.log("end"); controller.abort(); }; - }, [showLog, type, podName, isRunning]); + }, [showLog, type, podName]); useEffect(() => { if (currentPodName !== podName) { diff --git a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx index 14dc1eaa..ba26da23 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx @@ -207,8 +207,7 @@ export class ProjectStatus extends React.Component<Props, State> { useLogStore.setState({ showLog: true, type: 'container', - podName: pod.containerName, - isRunning: true + podName: pod.containerName }); }}> {pod.containerName} @@ -287,7 +286,7 @@ export class ProjectStatus extends React.Component<Props, State> { <Label icon={isRunning ? <Spinner isSVG diameter="16px" className="spinner"/> : icon} color={color}> {pipeline ? <Button variant="link" onClick={e => - useLogStore.setState({showLog: true, type: 'pipeline', podName: pipeline, isRunning: true}) + useLogStore.setState({showLog: true, type: 'pipeline', podName: pipeline}) }> {pipeline} </Button> diff --git a/karavan-web/karavan-app/src/main/webui/src/services/ServicesPage.tsx b/karavan-web/karavan-app/src/main/webui/src/services/ServicesPage.tsx index 87606ac9..b7dd8fde 100644 --- a/karavan-web/karavan-app/src/main/webui/src/services/ServicesPage.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/services/ServicesPage.tsx @@ -23,36 +23,24 @@ import {DeleteServiceModal} from "./DeleteServiceModal"; import {CreateServiceModal} from "./CreateServiceModal"; import {useProjectStore, useStatusesStore} from "../api/ProjectStore"; import {MainToolbar} from "../designer/MainToolbar"; -import {ContainerStatus, Project, ProjectType} from "../api/ProjectModels"; +import {Project, ProjectType} from "../api/ProjectModels"; import {KaravanApi} from "../api/KaravanApi"; import {DevService, Services, ServicesYaml} from "../api/ServiceModels"; import {shallow} from "zustand/shallow"; +import {ProjectLogPanel} from "../project/log/ProjectLogPanel"; export const ServicesPage = () => { const [services, setServices] = useState<Services>(); - const [containers, setContainers] = useStatusesStore((state) => [state.containers, state.setContainers], shallow); - const [operation, setOperation] = useState<'create' | 'delete' | 'none'>('none'); - const [loading, setLoading] = useState<boolean>(false); + const [containers] = useStatusesStore((state) => [state.containers, state.setContainers], shallow); + const [operation] = useState<'create' | 'delete' | 'none'>('none'); + const [loading] = useState<boolean>(false); useEffect(() => { getServices(); - const interval = setInterval(() => { - updateContainerStatuses() - }, 700); - return () => { - clearInterval(interval) - }; }, []); - function updateContainerStatuses() { - KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => { - setContainers(statuses); - setLoading(false); - }); - } - function getServices() { KaravanApi.getFiles(ProjectType.services, files => { const file = files.at(0); @@ -142,6 +130,7 @@ export const ServicesPage = () => { </PageSection> {["create"].includes(operation) && <CreateServiceModal/>} {["delete"].includes(operation) && <DeleteServiceModal/>} + <ProjectLogPanel/> </PageSection> ) } \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx b/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx index fab5456d..c5bc953a 100644 --- a/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/services/ServicesTableRow.tsx @@ -2,7 +2,7 @@ import React, {useState} from 'react'; import { Button, Tooltip, - Flex, FlexItem, Label, ToolbarContent, Toolbar, ToolbarItem, Spinner + Flex, FlexItem, Label, ToolbarContent, Toolbar, ToolbarItem, Spinner, TooltipPosition } from '@patternfly/react-core'; import '../designer/karavan.css'; import {ActionsColumn, ExpandableRowContent, Tbody, Td, Tr} from "@patternfly/react-table"; @@ -12,9 +12,11 @@ import {DevService} from "../api/ServiceModels"; import {ContainerStatus} from "../api/ProjectModels"; import PauseIcon from "@patternfly/react-icons/dist/esm/icons/pause-icon"; import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon"; -import {useAppConfigStore} from "../api/ProjectStore"; +import {useAppConfigStore, useLogStore} from "../api/ProjectStore"; import {shallow} from "zustand/shallow"; import {KaravanApi} from "../api/KaravanApi"; +import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon"; +import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon"; interface Props { index: number @@ -80,7 +82,8 @@ export const ServicesTableRow = (props: Props) => { const container = props.container; const isRunning = container?.state === 'running'; const inTransit = container?.inTransit; - const color = container?.state === 'running' ? "green" : "grey"; + const color = isRunning ? "green" : "grey"; + const icon = isRunning ? <UpIcon/> : <DownIcon/>; return ( <Tbody isExpanded={isExpanded}> <Tr key={service.container_name}> @@ -96,7 +99,17 @@ export const ServicesTableRow = (props: Props) => { modifier={"fitContent"}> </Td> <Td> - <Label color={color}>{service.container_name}</Label> + {container && <Label icon={icon} color={color}> + <Tooltip content={"Show log"} position={TooltipPosition.bottom}> + <Button variant="link" isDisabled={!isRunning} + onClick={e => { + useLogStore.setState({showLog: true, type: 'container', podName: container.containerName}); + }}> + {service.container_name} + </Button> + </Tooltip> + </Label>} + {!container && <Label color={color}>{service.container_name}</Label>} </Td> <Td>{service.container_name}</Td> <Td>{service.image}</Td>