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 12f357320435bd6a5faabd61f936999a5865d432 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Sun Aug 25 12:45:04 2024 -0400 Frontend fixes --- karavan-app/src/main/webui/src/api/KaravanApi.tsx | 4 +- .../src/main/webui/src/project/DevModeToolbar.tsx | 5 +- .../src/main/webui/src/project/ProjectToolbar.tsx | 8 +-- .../main/webui/src/project/builder/BuildPanel.tsx | 11 ++-- .../main/webui/src/project/builder/ImagesPanel.tsx | 12 +++-- .../src/project/container/ContainerButtons.tsx | 2 +- .../src/project/container/DeploymentPanel.tsx | 61 +++++++++++++++++++--- .../webui/src/project/files/CreateFileModal.tsx | 4 +- 8 files changed, 78 insertions(+), 29 deletions(-) diff --git a/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/api/KaravanApi.tsx index 9a8e0f34..e883e424 100644 --- a/karavan-app/src/main/webui/src/api/KaravanApi.tsx +++ b/karavan-app/src/main/webui/src/api/KaravanApi.tsx @@ -478,7 +478,7 @@ export class KaravanApi { }); } - static async startDevModeContainer(project: Project, verbose: boolean, after: (res: AxiosResponse<string>) => void) { + static async startDevModeContainer(project: Project, verbose: boolean, after: (res: AxiosResponse<any>) => void) { instance.post('/ui/devmode' + (verbose ? '/--verbose' : ''), project) .then(res => { after(res); @@ -604,7 +604,7 @@ export class KaravanApi { type: 'devmode' | 'devservice' | 'project' | 'internal' | 'build' | 'unknown', name: string, command: 'deploy' | 'run' | 'pause' | 'stop' | 'delete', - pullImage: boolean, + pullImage: 'always' | 'ifNotExists' | 'never', after: (res: AxiosResponse<any> | any) => void) { instance.post('/ui/container/' + projectId + '/' + type + "/" + name, {command: command, pullImage: pullImage}) .then(res => { diff --git a/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx b/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx index f98fda4a..e8af4bcc 100644 --- a/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx +++ b/karavan-app/src/main/webui/src/project/DevModeToolbar.tsx @@ -31,7 +31,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 {useAppConfigStore, useLogStore, useProjectStore, useStatusesStore} from "../api/ProjectStore"; +import {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/running-icon"; @@ -45,13 +45,12 @@ interface Props { export function DevModeToolbar(props: Props) { - const [config] = useAppConfigStore((state) => [state.config], shallow) const [project, refreshTrace] = useProjectStore((state) => [state.project, state.refreshTrace], shallow) const [containers] = useStatusesStore((state) => [state.containers], shallow); const [verbose, setVerbose] = useState(false); const [showSpinner, setShowSpinner] = useState(false); const [setShowLog] = useLogStore((s) => [s.setShowLog], shallow); - const [currentContainerStatus, setCurrentContainerStatus] = useState<ContainerStatus>(); + const [currentContainerStatus] = useState<ContainerStatus>(); const containerStatuses = containers.filter(c => c.projectId === project.projectId) || []; diff --git a/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx b/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx index 56e16d33..5b1f4d6b 100644 --- a/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx +++ b/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx @@ -22,7 +22,7 @@ import { } from '@patternfly/react-core'; import '../designer/karavan.css'; import {DevModeToolbar} from "./DevModeToolbar"; -import {useFileStore, useProjectStore} from "../api/ProjectStore"; +import {useAppConfigStore, useFileStore, useProjectStore} from "../api/ProjectStore"; import {shallow} from "zustand/shallow"; import {EditorToolbar} from "../editor/EditorToolbar"; import {BUILD_IN_PROJECTS,} from "../api/ProjectModels"; @@ -32,6 +32,8 @@ export function ProjectToolbar() { const [project] = useProjectStore((s) => [s.project, s.tabIndex], shallow) const [file] = useFileStore((state) => [state.file], shallow) + const [config] = useAppConfigStore((s) => [s.config], shallow); + const isDev = config.environment === 'dev'; const isBuildInProject = BUILD_IN_PROJECTS.includes(project.projectId); @@ -46,8 +48,8 @@ export function ProjectToolbar() { function getProjectToolbar() { return (<Toolbar id="toolbar-group-types"> <ToolbarContent> - {!isBuildInProject && <DevModeToolbar/>} - {isBuildInProject && <ResourceToolbar/>} + {!isBuildInProject && isDev && <DevModeToolbar/>} + {(isBuildInProject || !isDev) && <ResourceToolbar/>} </ToolbarContent> </Toolbar>) } diff --git a/karavan-app/src/main/webui/src/project/builder/BuildPanel.tsx b/karavan-app/src/main/webui/src/project/builder/BuildPanel.tsx index aee7a37c..a771a9be 100644 --- a/karavan-app/src/main/webui/src/project/builder/BuildPanel.tsx +++ b/karavan-app/src/main/webui/src/project/builder/BuildPanel.tsx @@ -31,14 +31,13 @@ import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon import ClockIcon from "@patternfly/react-icons/dist/esm/icons/clock-icon"; 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 {useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; import {shallow} from "zustand/shallow"; import {EventBus} from "../../designer/utils/EventBus"; import {getShortCommit} from "../../util/StringUtils"; export function BuildPanel () { - const [config] = useAppConfigStore((state) => [state.config], shallow); const [project] = useProjectStore((s) => [s.project], shallow); const [setShowLog] = useLogStore((s) => [s.setShowLog], shallow); const [containers, deployments, camels] = @@ -52,7 +51,7 @@ export function BuildPanel () { function deleteEntity() { const buildName = getBuildName(); if (buildName) { - KaravanApi.manageContainer(project.projectId, 'build', buildName, 'delete', false,res => { + KaravanApi.manageContainer(project.projectId, 'build', buildName, 'delete', 'never',res => { EventBus.sendAlert("Container deleted", "Container " + buildName + " deleted", 'info') setShowLog(false, 'container', undefined) }); @@ -75,9 +74,7 @@ export function BuildPanel () { function buildButton() { const status = containers.filter(c => c.projectId === project.projectId && c.type === 'build').at(0); const isRunning = status?.state === 'running'; - const tooltip = config.infrastructure === 'kubernetes' ? "Build and Deploy project" : "Build project" - const buttonTitle = config.infrastructure === 'kubernetes' ? "Deploy" : "Build" - return (<Tooltip content={tooltip} position={"left"}> + return (<Tooltip content={"Build project"} position={"left"}> <Button isLoading={isBuilding ? true : undefined} isDisabled={isBuilding || isRunning || isPushing} size="sm" @@ -85,7 +82,7 @@ export function BuildPanel () { className="project-button dev-action-button" icon={!isBuilding ? <BuildIcon/> : <div></div>} onClick={e => build()}> - {isBuilding ? "..." : buttonTitle} + {isBuilding ? "..." : "Build"} </Button> </Tooltip>) } diff --git a/karavan-app/src/main/webui/src/project/builder/ImagesPanel.tsx b/karavan-app/src/main/webui/src/project/builder/ImagesPanel.tsx index b4dea27d..1d137edf 100644 --- a/karavan-app/src/main/webui/src/project/builder/ImagesPanel.tsx +++ b/karavan-app/src/main/webui/src/project/builder/ImagesPanel.tsx @@ -37,7 +37,7 @@ import { CardBody, CardHeader, HelperTextItem, HelperText } from '@patternfly/react-core'; import '../../designer/karavan.css'; -import {useFilesStore, useProjectStore} from "../../api/ProjectStore"; +import {useAppConfigStore, useFilesStore, useProjectStore} from "../../api/ProjectStore"; import {shallow} from "zustand/shallow"; import {Table} from "@patternfly/react-table/deprecated"; import {Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table"; @@ -61,6 +61,8 @@ export function ImagesPanel() { const [imageName, setImageName] = useState<string>(); const [commitChanges, setCommitChanges] = useState<boolean>(false); const [commitMessage, setCommitMessage] = useState(''); + const [config] = useAppConfigStore((s) => [s.config], shallow); + const isDev = config.environment === 'dev'; function setProjectImage() { if (imageName) { @@ -247,10 +249,10 @@ export function ImagesPanel() { spaceItems={{default: 'spaceItemsNone'}}> <FlexItem> <Tooltip content={"Delete image"} position={"bottom"}> - <Button variant={"plain"} + <Button variant={"link"} className='dev-action-button' icon={<DeleteIcon/>} - isDisabled={fullName === projectImage} + isDisabled={fullName === projectImage || !isDev} onClick={e => { setImageName(fullName); setShowDeleteConfirmation(true); @@ -260,9 +262,9 @@ export function ImagesPanel() { </FlexItem> <FlexItem> <Tooltip content="Set project image" position={"bottom"}> - <Button variant={"plain"} + <Button variant={"link"} className='dev-action-button' - isDisabled={fullName === projectImage} + isDisabled={fullName === projectImage || !isDev} onClick={e => { setImageName(fullName); setCommitMessage(commitMessage === '' ? new Date().toLocaleString() : commitMessage); diff --git a/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx b/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx index 50f05d39..23bede07 100644 --- a/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx +++ b/karavan-app/src/main/webui/src/project/container/ContainerButtons.tsx @@ -50,7 +50,7 @@ export function ContainerButtons (props: Props) { const isLoading = status === 'wip'; function act() { - KaravanApi.manageContainer(project.projectId, 'project', project.projectId, actionType, pullImage,res => { + KaravanApi.manageContainer(project.projectId, 'project', project.projectId, actionType, pullImage ? 'always' : 'never',res => { const response = res?.response; if (response?.status === 500) { EventBus.sendAlert('Error', response.data !== undefined && response.data.length > 0 ? response.data : response.statusText, 'warning') diff --git a/karavan-app/src/main/webui/src/project/container/DeploymentPanel.tsx b/karavan-app/src/main/webui/src/project/container/DeploymentPanel.tsx index 53367bd0..6e4b0aa8 100644 --- a/karavan-app/src/main/webui/src/project/container/DeploymentPanel.tsx +++ b/karavan-app/src/main/webui/src/project/container/DeploymentPanel.tsx @@ -27,10 +27,11 @@ import { 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 {useAppConfigStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore"; +import {useProjectStore, useStatusesStore} from "../../api/ProjectStore"; import {shallow} from "zustand/shallow"; import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon"; import RolloutIcon from "@patternfly/react-icons/dist/esm/icons/process-automation-icon"; +import DeployIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon"; import {KaravanApi} from "../../api/KaravanApi"; import {EventBus} from "../../designer/utils/EventBus"; @@ -44,6 +45,7 @@ export function DeploymentPanel (props: Props) { const [ deployments] = useStatusesStore((s) => [s.deployments], shallow); const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false); + const [showDeployConfirmation, setShowDeployConfirmation] = useState<boolean>(false); const [showRolloutConfirmation, setShowRolloutConfirmation] = useState<boolean>(false); function deleteDeployment() { @@ -58,13 +60,22 @@ export function DeploymentPanel (props: Props) { function rolloutDeployment () { KaravanApi.rolloutDeployment(project.projectId, props.env, res => { - console.log(res) if (res.status === 200) { EventBus.sendAlert("Rolled out", "Rolled out: " + project.projectId, 'info'); } }); } + function startDeployment(){ + KaravanApi.startDeployment(project.projectId, props.env, res => { + if (res.status === 200) { + EventBus.sendAlert("Started", "Deployment started for " + project.projectId, 'info'); + } else { + EventBus.sendAlert("Error", res.data, 'danger'); + } + }); + } + function getDeleteConfirmation() { return (<Modal className="modal-delete" @@ -104,13 +115,35 @@ export function DeploymentPanel (props: Props) { <Button key="cancel" variant="link" onClick={e => setShowRolloutConfirmation(false)}>Cancel</Button> ]} - onEscapePress={e => setShowDeleteConfirmation(false)}> + onEscapePress={e => setShowRolloutConfirmation(false)}> <div>{"Rollout deployment " + project.projectId + "?"}</div> </Modal>) } + function getDeployConfirmation() { + return (<Modal + className="modal-delete" + title="Confirmation" + isOpen={showDeployConfirmation} + onClose={() => setShowDeployConfirmation(false)} + actions={[ + <Button key="confirm" variant="primary" onClick={e => { + if (project.projectId) { + startDeployment(); + setShowDeployConfirmation(false); + } + }}>Deploy + </Button>, + <Button key="cancel" variant="link" + onClick={e => setShowDeployConfirmation(false)}>Cancel</Button> + ]} + onEscapePress={e => setShowDeleteConfirmation(false)}> + <div>{"Deploy " + project.projectId + "?"}</div> + </Modal>) + } + function rolloutButton() { - return (<Tooltip content="Rollout deployment" position={"left"}> + return ( <Button size="sm" variant="secondary" className="project-button dev-action-button" icon={<RolloutIcon/>} @@ -118,8 +151,20 @@ export function DeploymentPanel (props: Props) { setShowRolloutConfirmation(true); }}> {"Rollout"} + </Button>) + } + + function deployButton() { + return ( + <Button size="sm" variant="primary" + className="project-button dev-action-button" + icon={<DeployIcon/>} + onClick={e => { + setShowDeployConfirmation(true); + }}> + {"Deploy"} </Button> - </Tooltip>) + ) } const deploymentStatus = deployments.find(d => d.projectId === project?.projectId); @@ -128,7 +173,7 @@ export function DeploymentPanel (props: Props) { && deploymentStatus?.replicas === deploymentStatus?.readyReplicas) return ( <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}> - <FlexItem> + <FlexItem flex={{default: 'flex_2'}}> {deploymentStatus && <LabelGroup numLabels={3}> <Tooltip content={"Ready Replicas / Replicas"} position={"left"}> <Label icon={ok ? <UpIcon/> : <DownIcon/>} @@ -149,9 +194,11 @@ export function DeploymentPanel (props: Props) { </LabelGroup>} {deploymentStatus === undefined && <Label icon={<DownIcon/>} color={"grey"}>No deployments</Label>} </FlexItem> - <FlexItem>{props.env === "dev" && rolloutButton()}</FlexItem> + <FlexItem>{rolloutButton()}</FlexItem> + <FlexItem>{deployButton()}</FlexItem> {showDeleteConfirmation && getDeleteConfirmation()} {showRolloutConfirmation && getRolloutConfirmation()} + {showDeployConfirmation && getDeployConfirmation()} </Flex> ) } diff --git a/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx b/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx index 20d76296..39625adc 100644 --- a/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx +++ b/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx @@ -84,7 +84,9 @@ export function CreateFileModal() { function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void { if (event.key === 'Enter') { - handleSubmit(onSubmit)() + event.preventDefault(); + event.stopPropagation(); + handleSubmit(onSubmit)(); } }