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 482c50f108928c6c1c078886f2ec0b1c3c0637d3 Author: Marat Gubaidullin <[email protected]> AuthorDate: Fri Sep 8 19:45:53 2023 -0400 Kubernetesless forst full process for #817 --- .../src/main/webui/src/project/ProjectPanel.tsx | 4 + .../src/main/webui/src/project/ProjectToolbar.tsx | 8 +- .../main/webui/src/project/build/BuildPanel.tsx | 100 +++++++----------- .../webui/src/project/build/ContainersPanel.tsx | 112 --------------------- .../webui/src/project/build/ProjectBuildTab.tsx | 9 +- .../ContainerButtons.tsx} | 95 ++++++++++------- .../webui/src/project/container/ContainerPanel.tsx | 90 +++++++++++++++++ .../ProjectContainerTab.tsx} | 14 +-- 8 files changed, 202 insertions(+), 230 deletions(-) diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx index 27246306..6838dbf1 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx @@ -12,6 +12,8 @@ import {ProjectBuildTab} from "./build/ProjectBuildTab"; import {ProjectService} from "../api/ProjectService"; import {shallow} from "zustand/shallow"; import {ImagesPanel} from "./build/ImagesPanel"; +import {ContainerButtons} from "./container/ContainerButtons"; +import {ProjectContainerTab} from "./container/ProjectContainerTab"; export function ProjectPanel () { @@ -40,6 +42,7 @@ export function ProjectPanel () { <Tab eventKey="dashboard" title="Dashboard"/> <Tab eventKey="trace" title="Trace"/> <Tab eventKey="build" title="Build"/> + <Tab eventKey="container" title="Container"/> </Tabs>} </FlexItem> <FlexItem> @@ -51,6 +54,7 @@ export function ProjectPanel () { {tab === 'trace' && project && <TraceTab/>} {tab === 'build' && <ProjectBuildTab/>} {tab === 'build' && <ImagesPanel/>} + {tab === 'container' && <ProjectContainerTab/>} </> } </FlexItem> diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx index 0dd876cc..84f0cd2c 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx @@ -109,7 +109,7 @@ export function ProjectToolbar () { return (<Toolbar id="toolbar-group-types"> <ToolbarContent> {isRunnable() && <DevModeToolbar/>} - {isBuild() && <BuildToolbar/>} + {isBuildContainer() && <BuildToolbar/>} </ToolbarContent> </Toolbar>) } @@ -127,11 +127,11 @@ export function ProjectToolbar () { } function isRunnable(): boolean { - return !isKameletsProject() && !isTemplatesProject() && !isServicesProject() && tabIndex !== 'build'; + return !isKameletsProject() && !isTemplatesProject() && !isServicesProject() && !['build', 'container'].includes(tabIndex.toString()); } - function isBuild(): boolean { - return !isKameletsProject() && !isTemplatesProject() && !isServicesProject() && tabIndex === 'build'; + function isBuildContainer(): boolean { + return !isKameletsProject() && !isTemplatesProject() && !isServicesProject() && ['build', 'container'].includes(tabIndex.toString()); } function allowAddFiles(): boolean { diff --git a/karavan-web/karavan-app/src/main/webui/src/project/build/BuildPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/build/BuildPanel.tsx index 752f496c..eb4efa03 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/build/BuildPanel.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/build/BuildPanel.tsx @@ -16,13 +16,9 @@ import TagIcon from "@patternfly/react-icons/dist/esm/icons/tag-icon"; import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon"; import {useAppConfigStore, useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; import {shallow} from "zustand/shallow"; -import {ContainersPanel} from "./ContainersPanel"; +import {EventBus} from "../../designer/utils/EventBus"; -interface Props { - env: string, -} - -export function BuildPanel (props: Props) { +export function BuildPanel () { const [config] = useAppConfigStore((state) => [state.config], shallow) const [project] = useProjectStore((s) => [s.project], shallow); @@ -32,31 +28,18 @@ export function BuildPanel (props: Props) { const [isPushing, setIsPushing] = useState<boolean>(false); const [isBuilding, setIsBuilding] = useState<boolean>(false); const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false); - const [deleteEntityType, setDeleteEntityType] = useState<'pod' | 'deployment' | 'build'>('pod'); const [deleteEntityName, setDeleteEntityName] = useState<string>(); - const [deleteEntityEnv, setDeleteEntityEnv] = useState<string>(); - const [tag, setTag] = useState<string>(new Date().toISOString().substring(0,19).replaceAll(':', '-')); + const [tag, setTag] = useState<string>( + new Date().toISOString().substring(0,19).replaceAll(':', '').replaceAll('-', '') + ); - function deleteEntity(type: 'pod' | 'deployment' | 'build', name: string, environment: string) { - switch (type) { - case "deployment": - KaravanApi.deleteDeployment(environment, name, (res: any) => { - // if (Array.isArray(res) && Array.from(res).length > 0) - // onRefresh(); - }); - break; - case "pod": - KaravanApi.deleteContainer(environment, 'project', name, (res: any) => { - // if (Array.isArray(res) && Array.from(res).length > 0) - // onRefresh(); - }); - break; - case "build": - KaravanApi.stopBuild(environment, name, (res: any) => { - // if (Array.isArray(res) && Array.from(res).length > 0) - // onRefresh(); - }); - break; + function deleteEntity() { + if (deleteEntityName) { + KaravanApi.stopBuild('dev', deleteEntityName, (res: any) => { + if (res.status === 200) { + EventBus.sendAlert("Build deleted", "Build deleted: " + deleteEntityName, 'info'); + } + }); } } @@ -72,7 +55,7 @@ export function BuildPanel (props: Props) { }); } - function buildButton(env: string) { + function buildButton() { const status = pipelineStatuses.filter(p => p.projectId === project.projectId).at(0); const isRunning = status?.result === 'Running'; return (<Tooltip content="Start build" position={"left"}> @@ -95,8 +78,6 @@ export function BuildPanel (props: Props) { icon={<DeleteIcon/>} onClick={e => { setShowDeleteConfirmation(true); - setDeleteEntityType("deployment"); - setDeleteEntityEnv(env); setDeleteEntityName(project?.projectId); }}> {"Delete"} @@ -166,8 +147,6 @@ export function BuildPanel (props: Props) { className="labeled-button" variant="link" onClick={e => { setShowDeleteConfirmation(true); - setDeleteEntityType("build"); - setDeleteEntityEnv(env); setDeleteEntityName(pipeline); }}></Button> </Tooltip>} @@ -178,12 +157,12 @@ export function BuildPanel (props: Props) { </LabelGroup> </Tooltip> </FlexItem> - <FlexItem>{env === "dev" && buildButton(env)}</FlexItem> + <FlexItem>{buildButton()}</FlexItem> </Flex> ) } - function getBuildState(env: string) { + function getBuildState() { const status = containers.filter(c => c.projectId === project.projectId && c.type === 'build').at(0); const buildName = status?.containerName; const state = status?.state; @@ -202,9 +181,6 @@ export function BuildPanel (props: Props) { <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}> <FlexItem> <LabelGroup numLabels={3}> - <Label isEditable={!isRunning} onEditComplete={(_, v) => setTag(v)} - icon={<TagIcon className="not-spinner"/>} - color={color}>{tag}</Label> <Label icon={isRunning ? <Spinner diameter="16px" className="spinner"/> : icon} color={color}> {buildName @@ -220,8 +196,6 @@ export function BuildPanel (props: Props) { className="labeled-button" variant="link" onClick={e => { setShowDeleteConfirmation(true); - setDeleteEntityType("build"); - setDeleteEntityEnv(env); setDeleteEntityName(buildName); }}></Button> </Tooltip>} @@ -231,11 +205,24 @@ export function BuildPanel (props: Props) { color={color}>{buildTime + "s"}</Label>} </LabelGroup> </FlexItem> - <FlexItem>{env === "dev" && buildButton(env)}</FlexItem> + <FlexItem>{buildButton()}</FlexItem> </Flex> ) } + function getBuildTag() { + const status = containers.filter(c => c.projectId === project.projectId && c.type === 'build').at(0); + const state = status?.state; + const isRunning = state === 'running'; + const isExited = state === 'exited'; + const color = isExited ? "grey" : (isRunning ? "blue" : "grey"); + return ( + <Label isEditable={!isRunning} onEditComplete={(_, v) => setTag(v)} + icon={<TagIcon className="not-spinner"/>} + color={color}>{tag}</Label> + ) + } + function getDeleteConfirmation() { return (<Modal className="modal-delete" @@ -244,8 +231,8 @@ export function BuildPanel (props: Props) { onClose={() => setShowDeleteConfirmation(false)} actions={[ <Button key="confirm" variant="primary" onClick={e => { - if (deleteEntityEnv && deleteEntityName && deleteEntity) { - deleteEntity(deleteEntityType, deleteEntityName, deleteEntityEnv); + if (deleteEntityName && deleteEntity) { + deleteEntity(); setShowDeleteConfirmation(false); } }}>Delete @@ -254,39 +241,24 @@ export function BuildPanel (props: Props) { onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button> ]} onEscapePress={e => setShowDeleteConfirmation(false)}> - <div>{"Delete " + deleteEntityType + " " + deleteEntityName + "?"}</div> + <div>{"Delete build " + deleteEntityName + "?"}</div> </Modal>) } - const env = props.env; return ( <Card className="project-status"> <CardBody> <DescriptionList isHorizontal horizontalTermWidthModifier={{default: '20ch'}}> <DescriptionListGroup> - <DescriptionListTerm>Environment</DescriptionListTerm> - <DescriptionListDescription> - <Badge className="badge">{env}</Badge> - </DescriptionListDescription> - </DescriptionListGroup> - <DescriptionListGroup> - <DescriptionListTerm>Build container with tag</DescriptionListTerm> + <DescriptionListTerm>Tag</DescriptionListTerm> <DescriptionListDescription> - {getBuildState(env)} + {getBuildTag()} </DescriptionListDescription> </DescriptionListGroup> - {config.infrastructure === 'kubernetes' && - <DescriptionListGroup> - <DescriptionListTerm>Deployment</DescriptionListTerm> - <DescriptionListDescription> - {getReplicasPanel(env)} - </DescriptionListDescription> - </DescriptionListGroup> - } <DescriptionListGroup> - <DescriptionListTerm>Containers</DescriptionListTerm> + <DescriptionListTerm>Build container</DescriptionListTerm> <DescriptionListDescription> - <ContainersPanel env={props.env}/> + {getBuildState()} </DescriptionListDescription> </DescriptionListGroup> </DescriptionList> diff --git a/karavan-web/karavan-app/src/main/webui/src/project/build/ContainersPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/build/ContainersPanel.tsx deleted file mode 100644 index 87a43f0f..00000000 --- a/karavan-web/karavan-app/src/main/webui/src/project/build/ContainersPanel.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import React, {useState} from 'react'; -import { - Button, Tooltip, Flex, FlexItem, LabelGroup, Label, Modal -} from '@patternfly/react-core'; -import '../../designer/karavan.css'; -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"; -import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon"; -import {ContainerStatus} from "../../api/ProjectModels"; -import {useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; -import {shallow} from "zustand/shallow"; - -interface Props { - env: string, -} - -export function ContainersPanel (props: Props) { - - const [project] = useProjectStore((s) => [s.project], shallow); - const [setShowLog] = useLogStore((s) => [s.setShowLog], shallow); - const [containers, deployments, camels, pipelineStatuses] = - useStatusesStore((s) => [s.containers, s.deployments, s.camels, s.pipelineStatuses], shallow); - const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false); - const [deleteEntityName, setDeleteEntityName] = useState<string>(); - const [deleteEntityEnv, setDeleteEntityEnv] = useState<string>(); - - function deleteContainer(name: string, environment: string) { - KaravanApi.deleteContainer(environment, 'project', name, (res: any) => { - // if (Array.isArray(res) && Array.from(res).length > 0) - // onRefresh(); - }); - } - - function deleteButton(env: string) { - return (<Tooltip content="Delete container" position={"left"}> - <Button size="sm" variant="secondary" - className="project-button" - icon={<DeleteIcon/>} - onClick={e => { - setShowDeleteConfirmation(true); - setDeleteEntityEnv(env); - setDeleteEntityName(project?.projectId); - }}> - {"Delete"} - </Button> - </Tooltip>) - } - - function getDeleteConfirmation() { - return (<Modal - className="modal-delete" - title="Confirmation" - isOpen={showDeleteConfirmation} - onClose={() => setShowDeleteConfirmation(false)} - actions={[ - <Button key="confirm" variant="primary" onClick={e => { - if (deleteEntityEnv && deleteEntityName) { - deleteContainer(deleteEntityName, deleteEntityEnv); - setShowDeleteConfirmation(false); - } - }}>Delete - </Button>, - <Button key="cancel" variant="link" - onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button> - ]} - onEscapePress={e => setShowDeleteConfirmation(false)}> - <div>{"Delete container " + deleteEntityName + "?"}</div> - </Modal>) - } - - const env = props.env; - const conts = containers.filter(d => d.projectId === project?.projectId && d.type === 'project'); - return ( - <Flex justifyContent={{default: "justifyContentSpaceBetween"}} - alignItems={{default: "alignItemsFlexStart"}}> - <FlexItem> - {conts.length === 0 && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>} - <LabelGroup numLabels={2} isVertical> - {conts.map((pod: ContainerStatus) => { - const ready = pod.state === 'running'; - return ( - <Tooltip key={pod.containerName} content={pod.state}> - <Label icon={ready ? <UpIcon/> : <DownIcon/>} color={ready ? "green" : "red"}> - <Button variant="link" className="labeled-button" - onClick={e => { - setShowLog(true,'container', pod.containerName); - }}> - {pod.containerName} - </Button> - <Tooltip content={"Delete Container"}> - <Button icon={<DeleteIcon/>} - className="labeled-button" - variant="link" - onClick={e => { - setShowDeleteConfirmation(true); - setDeleteEntityEnv(env); - setDeleteEntityName(pod.containerName); - }}></Button> - </Tooltip> - </Label> - </Tooltip> - ) - } - )} - </LabelGroup> - </FlexItem> - <FlexItem>{env === "dev" && deleteButton(env)}</FlexItem> - {showDeleteConfirmation && getDeleteConfirmation()} - </Flex> - ) -} diff --git a/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx index e761bbcb..7c980820 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx @@ -2,20 +2,13 @@ import React from 'react'; import '../../designer/karavan.css'; import {BuildPanel} from "./BuildPanel"; import {PageSection} from "@patternfly/react-core"; -import {useAppConfigStore, useProjectStore} from "../../api/ProjectStore"; export function ProjectBuildTab () { - const {config} = useAppConfigStore(); - const {project} = useProjectStore(); - return ( <PageSection className="project-tab-panel project-build-panel" padding={{default: "padding"}}> <div> - {/*{["dev", "test", "prod"].map(env =>*/} - {config.environments.map(env => - <BuildPanel key={env} env={env}/> - )} + <BuildPanel/> </div> </PageSection> ) diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ContainerPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx similarity index 53% rename from karavan-web/karavan-app/src/main/webui/src/project/ContainerPanel.tsx rename to karavan-web/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx index c32fb4a7..1fafb4d8 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/ContainerPanel.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx @@ -1,24 +1,19 @@ -import React from 'react'; -import {Button, Flex, FlexItem, Label, Spinner, Tooltip, TooltipPosition} from '@patternfly/react-core'; -import '../designer/karavan.css'; +import React, {useState} from 'react'; +import {Button, Flex, FlexItem, Modal, Spinner, Tooltip, TooltipPosition} from '@patternfly/react-core'; +import '../../designer/karavan.css'; import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon"; -import {useAppConfigStore, useDevModeStore, useLogStore, useProjectStore, useStatusesStore} from "../api/ProjectStore"; +import {useAppConfigStore, useDevModeStore, useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; import {shallow} from "zustand/shallow"; -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"; import RunIcon from "@patternfly/react-icons/dist/esm/icons/play-icon"; -import {ProjectService} from "../api/ProjectService"; -import ReloadIcon from "@patternfly/react-icons/dist/esm/icons/bolt-icon"; -import {KaravanApi} from "../api/KaravanApi"; -import {ProjectEventBus} from "../api/ProjectEventBus"; -import {EventBus} from "../designer/utils/EventBus"; +import {KaravanApi} from "../../api/KaravanApi"; import StopIcon from "@patternfly/react-icons/dist/js/icons/stop-icon"; + interface Props { - reloadOnly?: boolean + env: string, } -export function ContainerPanel (props: Props) { +export function ContainerButtons (props: Props) { const [config] = useAppConfigStore((state) => [state.config], shallow) const [status] = useDevModeStore((state) => [state.status], shallow) @@ -26,29 +21,61 @@ export function ContainerPanel (props: Props) { const [containers] = useStatusesStore((state) => [state.containers], shallow); const [setShowLog] = useLogStore((s) => [s.setShowLog], shallow); + const [showConfirmation, setShowConfirmation] = useState<boolean>(false); + const [actionType, setActionType] = useState<'run' | 'stop' | 'delete'>('run'); + 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 icon = isRunning ? <UpIcon/> : <DownIcon/>; + + function act() { + switch (actionType) { + case "run": + KaravanApi.manageContainer(props.env, 'project', project.projectId, 'run', res => { + setShowLog(false, 'container', undefined) + }); + break; + case "stop": + KaravanApi.manageContainer(props.env, 'project', project.projectId, 'stop', res => { + setShowLog(false, 'container', undefined) + }); + break; + case "delete": + KaravanApi.manageContainer(props.env, 'project', project.projectId, 'delete', res => { + setShowLog(false, 'container', undefined) + }); + break; + } + } + + function getDeleteConfirmation() { + return (<Modal + className="modal-delete" + title="Confirmation" + isOpen={showConfirmation} + onClose={() => setShowConfirmation(false)} + actions={[ + <Button key="confirm" variant="primary" onClick={e => { + if (actionType && project.projectId) { + act(); + setShowConfirmation(false); + } + }}>Delete + </Button>, + <Button key="cancel" variant="link" + onClick={e => setShowConfirmation(false)}>Cancel</Button> + ]} + onEscapePress={e => setShowConfirmation(false)}> + <div>{"Confirm " + actionType + " container?"}</div> + </Modal>) + } return (<Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}> <FlexItem> {(inTransit || isLoading) && <Spinner size="lg" aria-label="spinner"/>} </FlexItem> - {containerStatus?.containerId && <FlexItem> - <Label icon={icon} color={color}> - <Tooltip content={"Show log"} position={TooltipPosition.bottom}> - <Button className='labeled-button' variant="link" isDisabled={!isRunning} - onClick={e => - setShowLog(true, 'container', containerStatus.containerName)}> - {containerStatus.containerName} - </Button> - </Tooltip> - </Label> - </FlexItem>} {!isRunning && <FlexItem> <Tooltip content="Run container" position={TooltipPosition.bottom}> <Button size="sm" @@ -56,9 +83,8 @@ export function ContainerPanel (props: Props) { variant={"primary"} icon={<RunIcon/>} onClick={() => { - KaravanApi.manageContainer('dev', 'project', project.projectId, 'run', res => { - setShowLog(false, 'container', undefined) - }); + setActionType('run'); + setShowConfirmation(true); }}> {"Run"} </Button> @@ -72,9 +98,8 @@ export function ContainerPanel (props: Props) { variant={"control"} icon={<StopIcon/>} onClick={() => { - KaravanApi.manageContainer('dev', 'project', project.projectId, 'stop', res => { - setShowLog(false, 'container', undefined) - }); + setActionType('stop'); + setShowConfirmation(true); }}> </Button> </Tooltip> @@ -87,12 +112,12 @@ export function ContainerPanel (props: Props) { variant={"control"} icon={<DeleteIcon/>} onClick={() => { - KaravanApi.manageContainer('dev', 'project', project.projectId, 'delete', res => { - setShowLog(false, 'container', undefined) - }); + setActionType('delete'); + setShowConfirmation(true); }}> </Button> </Tooltip> </FlexItem> + {showConfirmation && getDeleteConfirmation()} </Flex>); } \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/project/container/ContainerPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/container/ContainerPanel.tsx new file mode 100644 index 00000000..f1bda323 --- /dev/null +++ b/karavan-web/karavan-app/src/main/webui/src/project/container/ContainerPanel.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { + Badge, + Button, + Card, + CardBody, + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, + Flex, + FlexItem, + Label, + LabelGroup, + Tooltip, + TooltipPosition +} from '@patternfly/react-core'; +import '../../designer/karavan.css'; +import UpIcon from "@patternfly/react-icons/dist/esm/icons/running-icon"; +import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon"; +import {useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; +import {shallow} from "zustand/shallow"; +import {ContainerStatus} from "../../api/ProjectModels"; +import {ContainerButtons} from "./ContainerButtons"; + +interface Props { + env: string, +} + +export function ContainerPanel (props: Props) { + + const [project] = useProjectStore((s) => [s.project], shallow); + const [setShowLog] = useLogStore((s) => [s.setShowLog], shallow); + const [containers, deployments, camels, pipelineStatuses] = + useStatusesStore((s) => [s.containers, s.deployments, s.camels, s.pipelineStatuses], shallow); + + function getButtons() { + const env = props.env; + const conts = containers.filter(d => d.projectId === project?.projectId && d.type === 'project'); + return ( + <Flex justifyContent={{default: "justifyContentSpaceBetween"}} + alignItems={{default: "alignItemsFlexStart"}}> + <FlexItem> + {conts.length === 0 && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>} + <LabelGroup numLabels={2} isVertical> + {conts.map((pod: ContainerStatus) => { + const ready = pod.state === 'running'; + return ( + <Tooltip key={pod.containerName} content={pod.state} position={TooltipPosition.left}> + <Label icon={ready ? <UpIcon/> : <DownIcon/>} color={ready ? "green" : "grey"}> + <Button variant="link" className="labeled-button" + onClick={e => { + setShowLog(true, 'container', pod.containerName); + }}> + {pod.containerName} + </Button> + </Label> + </Tooltip> + ) + } + )} + </LabelGroup> + </FlexItem> + <FlexItem>{env === "dev" && <ContainerButtons env={env}/>}</FlexItem> + </Flex> + ) + } + + const env = props.env; + return ( + <Card className="project-status"> + <CardBody> + <DescriptionList isHorizontal horizontalTermWidthModifier={{default: '20ch'}}> + <DescriptionListGroup> + <DescriptionListTerm>Environment</DescriptionListTerm> + <DescriptionListDescription> + <Badge className="badge">{env}</Badge> + </DescriptionListDescription> + </DescriptionListGroup> + <DescriptionListGroup> + <DescriptionListTerm>Containers</DescriptionListTerm> + <DescriptionListDescription> + {getButtons()} + </DescriptionListDescription> + </DescriptionListGroup> + </DescriptionList> + </CardBody> + </Card> + ) +} diff --git a/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/container/ProjectContainerTab.tsx similarity index 50% copy from karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx copy to karavan-web/karavan-app/src/main/webui/src/project/container/ProjectContainerTab.tsx index e761bbcb..08eb587a 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/container/ProjectContainerTab.tsx @@ -1,20 +1,20 @@ import React from 'react'; +import { + PageSection +} from '@patternfly/react-core'; import '../../designer/karavan.css'; -import {BuildPanel} from "./BuildPanel"; -import {PageSection} from "@patternfly/react-core"; -import {useAppConfigStore, useProjectStore} from "../../api/ProjectStore"; +import {useAppConfigStore} from "../../api/ProjectStore"; +import {ContainerPanel} from "./ContainerPanel"; -export function ProjectBuildTab () { +export function ProjectContainerTab() { const {config} = useAppConfigStore(); - const {project} = useProjectStore(); return ( <PageSection className="project-tab-panel project-build-panel" padding={{default: "padding"}}> <div> - {/*{["dev", "test", "prod"].map(env =>*/} {config.environments.map(env => - <BuildPanel key={env} env={env}/> + <ContainerPanel key={env} env={env}/> )} </div> </PageSection>
