You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/05/04 01:50:32 UTC

[camel-karavan] 03/07: Container creator UI prototype for #757

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 0d04346da532154a5140d0665e69b26569f7a5e4
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed May 3 15:27:58 2023 -0400

    Container creator UI prototype for #757
---
 karavan-app/src/main/webui/src/api/KaravanApi.tsx  |   9 ++
 .../src/main/webui/src/projects/ProjectInfo.tsx    | 156 +++++++++++++++++----
 .../src/main/webui/src/projects/ProjectLog.tsx     |   2 +-
 .../src/main/webui/src/projects/ProjectPage.tsx    |   2 -
 .../main/webui/src/projects/ProjectPageToolbar.tsx | 145 +++++--------------
 5 files changed, 174 insertions(+), 140 deletions(-)

diff --git a/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 5210e0de..01ad51b7 100644
--- a/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -300,6 +300,15 @@ export class KaravanApi {
         });
     }
 
+    static async runProject(project: Project, after: (res: AxiosResponse<string>) => void) {
+        instance.post('/api/runner', project)
+            .then(res => {
+                after(res);
+            }).catch(err => {
+            after(err);
+        });
+    }
+
     static async pipelineRun(project: Project, environment: string, after: (res: AxiosResponse<any>) => void) {
         instance.post('/api/kubernetes/pipeline/' + environment, project)
             .then(res => {
diff --git a/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx
index cfdf0a88..9f9587b8 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx
@@ -3,10 +3,23 @@ import {
     DescriptionList,
     DescriptionListTerm,
     DescriptionListGroup,
-    DescriptionListDescription, Tooltip, Flex, FlexItem, Label
+    DescriptionListDescription,
+    Tooltip,
+    Flex,
+    FlexItem,
+    Label,
+    Button,
+    Modal,
+    ModalVariant,
+    Form,
+    FormGroup,
+    TextInput,
+    FormHelperText
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
-import {Project } from "./ProjectModels";
+import {Project} from "./ProjectModels";
+import {KaravanApi} from "../api/KaravanApi";
+import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
 
 
 interface Props {
@@ -17,62 +30,147 @@ interface Props {
 
 interface State {
     environment: string,
+    isPushing: boolean,
+    commitMessageIsOpen: boolean,
+    commitMessage: string
 }
 
 export class ProjectInfo extends React.Component<Props, State> {
 
     public state: State = {
-        environment: this.props.config.environment
+        environment: this.props.config.environment,
+        isPushing: false,
+        commitMessageIsOpen: false,
+        commitMessage: ''
     };
 
-    getDate(lastUpdate: number):string {
+    push = (after?: () => void) => {
+        this.setState({isPushing: true, commitMessageIsOpen: false});
+        const params = {
+            "projectId": this.props.project.projectId,
+            "message": this.state.commitMessage
+        };
+        KaravanApi.push(params, res => {
+            if (res.status === 200 || res.status === 201) {
+                this.setState({isPushing: false});
+                after?.call(this);
+                // this.props.onRefresh.call(this);
+            } else {
+                // Todo notification
+            }
+        });
+    }
+
+    getDate(lastUpdate: number): string {
         if (lastUpdate) {
             const date = new Date(lastUpdate);
-            return date.toDateString() + ' ' + date.toLocaleTimeString();
+            return date.toISOString().slice(0, 19).replace('T',' ');
         } else {
             return "N/A"
         }
     }
 
-    getLastUpdatePanel(){
+    getLastUpdatePanel() {
         const {project, needCommit} = this.props;
         const color = needCommit ? "grey" : "green";
         return (
-            <Flex direction={{default:"row"}} justifyContent={{default: "justifyContentFlexStart"}}>
+            <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentFlexStart"}}>
                 {project?.lastCommitTimestamp && project?.lastCommitTimestamp > 0 &&
                     <FlexItem>
                         <Label color={color}>{this.getDate(project?.lastCommitTimestamp)}</Label>
                     </FlexItem>
                 }
+            </Flex>
+        )
+    }
+
+    getCommitPanel() {
+        const {isPushing, commitMessage} = this.state;
+        const {project, needCommit} = this.props;
+        const color = needCommit ? "grey" : "green";
+        return (
+            <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentSpaceBetween"}}>
                 <FlexItem>
                     <Tooltip content={project?.lastCommit} position={"right"}>
-                        <Label color={color}>{project?.lastCommit ? project?.lastCommit?.substr(0, 7) : "-"}</Label>
+                        <Label
+                            color={color}>{project?.lastCommit ? project?.lastCommit?.substr(0, 18) : "-"}</Label>
                     </Tooltip>
                 </FlexItem>
-            </Flex>)
+                <FlexItem>
+                    <Tooltip content="Commit and push to git" position={"bottom-end"}>
+                        <Button isLoading={isPushing ? true : undefined}
+                                isSmall
+                                variant={needCommit ? "primary" : "secondary"}
+                                className="project-button"
+                                icon={!isPushing ? <PushIcon/> : <div></div>}
+                                onClick={() => this.setState({
+                                    commitMessageIsOpen: true,
+                                    commitMessage : commitMessage === '' ? new Date().toLocaleString() : commitMessage
+                                })}>
+                            {isPushing ? "..." : "Push"}
+                        </Button>
+                    </Tooltip>
+                </FlexItem>
+            </Flex>
+        )
+    }
+
+    getCommitModal() {
+        let {commitMessage, commitMessageIsOpen} = this.state;
+        return (
+            <Modal
+                title="Commit"
+                variant={ModalVariant.small}
+                isOpen={commitMessageIsOpen}
+                onClose={() => this.setState({commitMessageIsOpen: false})}
+                actions={[
+                    <Button key="confirm" variant="primary" onClick={() => this.push()}>Save</Button>,
+                    <Button key="cancel" variant="secondary"
+                            onClick={() => this.setState({commitMessageIsOpen: false})}>Cancel</Button>
+                ]}
+            >
+                <Form autoComplete="off" isHorizontal className="create-file-form">
+                    <FormGroup label="Message" fieldId="name" isRequired>
+                        <TextInput value={commitMessage} onChange={value => this.setState({commitMessage: value})}/>
+                        <FormHelperText isHidden={false} component="div"/>
+                    </FormGroup>
+                </Form>
+            </Modal>
+        )
     }
 
     render() {
         const {project} = this.props;
-        return (<DescriptionList isHorizontal>
-            <DescriptionListGroup>
-                <DescriptionListTerm>Project ID</DescriptionListTerm>
-                <DescriptionListDescription>{project?.projectId}</DescriptionListDescription>
-            </DescriptionListGroup>
-            <DescriptionListGroup>
-                <DescriptionListTerm>Name</DescriptionListTerm>
-                <DescriptionListDescription>{project?.name}</DescriptionListDescription>
-            </DescriptionListGroup>
-            <DescriptionListGroup>
-                <DescriptionListTerm>Description</DescriptionListTerm>
-                <DescriptionListDescription>{project?.description}</DescriptionListDescription>
-            </DescriptionListGroup>
-            <DescriptionListGroup>
-                <DescriptionListTerm>Updated</DescriptionListTerm>
-                <DescriptionListDescription>
-                    {this.getLastUpdatePanel()}
-                </DescriptionListDescription>
-            </DescriptionListGroup>
-        </DescriptionList>);
+        return (
+            <React.Fragment>
+                <DescriptionList isHorizontal>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Project ID</DescriptionListTerm>
+                        <DescriptionListDescription>{project?.projectId}</DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Name</DescriptionListTerm>
+                        <DescriptionListDescription>{project?.name}</DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Description</DescriptionListTerm>
+                        <DescriptionListDescription>{project?.description}</DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Updated</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            {this.getLastUpdatePanel()}
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Commit</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            {this.getCommitPanel()}
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                </DescriptionList>
+                {this.getCommitModal()}
+            </React.Fragment>
+        );
     }
 }
diff --git a/karavan-app/src/main/webui/src/projects/ProjectLog.tsx b/karavan-app/src/main/webui/src/projects/ProjectLog.tsx
index 3f314b9b..bd9cac9e 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectLog.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectLog.tsx
@@ -53,7 +53,7 @@ export class ProjectLog extends React.Component<Props, State> {
 
     showLogs = (type: 'container' | 'pipeline', name: string, environment: string) => {
         this.eventSource?.close();
-        this.eventSource = new EventSource("/api/logwatch/"+type+"/"+environment+"/"+name);
+        this.eventSource = new EventSource("/api/logwatch/"+type+"/"+environment+"/"+name, { withCredentials: true });
         this.eventSource.onerror = (event) => {
             this.eventSource?.close();
         }
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index 4ae933dd..052d8035 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -183,7 +183,6 @@ export class ProjectPage extends React.Component<Props, State> {
     tools = () => {
         return <ProjectPageToolbar key={this.state.key}
             project={this.props.project}
-            needCommit={this.needCommit()}
             file={this.state.file}
             mode={this.state.mode}
             isTemplates={this.isTemplatesProject()}
@@ -197,7 +196,6 @@ export class ProjectPage extends React.Component<Props, State> {
             setMode={mode => this.setState({mode: mode})}
             setCreateModalOpen={() => this.setState({isCreateModalOpen: true})}
             setUploadModalOpen={() => this.setState({isUploadModalOpen: true})}
-            onRefresh={this.onRefresh}
         />
     }
 
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx b/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx
index dc38966b..f72f7ce9 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx
@@ -7,7 +7,7 @@ import {
     FlexItem,
     ToggleGroup,
     ToggleGroupItem,
-    Checkbox, Tooltip, ToolbarItem, Modal, ModalVariant, Form, FormGroup, TextInput, FormHelperText
+    Checkbox, Tooltip, ToolbarItem
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import {Project, ProjectFile} from "./ProjectModels";
@@ -16,12 +16,9 @@ import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon";
 import DownloadImageIcon from "@patternfly/react-icons/dist/esm/icons/image-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
-import {KaravanApi} from "../api/KaravanApi";
 
 interface Props {
     project: Project,
-    needCommit: boolean,
     isTemplates: boolean,
     isKamelets: boolean,
     config: any,
@@ -33,79 +30,50 @@ interface Props {
     downloadImage: () => void,
     setCreateModalOpen: () => void,
     setUploadModalOpen: () => void,
-    onRefresh: () => void,
     setEditAdvancedProperties: (checked: boolean) => void,
     setMode: (mode: "design" | "code") => void,
 }
 
-interface State {
-    isPushing: boolean,
-    commitMessageIsOpen: boolean,
-    commitMessage: string
-}
-
-export class ProjectPageToolbar extends React.Component<Props> {
-
-    public state: State = {
-        isPushing: false,
-        commitMessageIsOpen: false,
-        commitMessage: ''
-    };
-
-    push = (after?: () => void) => {
-        this.setState({isPushing: true, commitMessageIsOpen: false});
-        const params = {
-            "projectId": this.props.project.projectId,
-            "message": this.state.commitMessage
-        };
-        KaravanApi.push(params, res => {
-            if (res.status === 200 || res.status === 201) {
-                this.setState({isPushing: false});
-                after?.call(this);
-                this.props.onRefresh.call(this);
-            } else {
-                // Todo notification
-            }
-        });
-    }
+export const ProjectPageToolbar = (props: Props) => {
 
-    getTemplatesToolbar() {
-        const {file, editAdvancedProperties, needCommit} = this.props;
-        const {isPushing} = this.state;
+    function getTemplatesToolbar() {
+        const {file, editAdvancedProperties, download, setCreateModalOpen, setUploadModalOpen} = props;
+        const isFile = file !== undefined;
         const isProperties = file !== undefined && file.name.endsWith("properties");
         return <Toolbar id="toolbar-group-types">
             <ToolbarContent>
                 <ToolbarItem>
-                    <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
+                    <Flex className="toolbar" direction={{default: "row"}} justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
                         {isProperties && <FlexItem>
                             <Checkbox
                                 id="advanced"
                                 label="Edit advanced"
                                 isChecked={editAdvancedProperties}
-                                onChange={checked => this.props.setEditAdvancedProperties.call(this, checked)}
+                                onChange={checked => props.setEditAdvancedProperties(checked)}
                             />
                         </FlexItem>}
-                        <FlexItem>
-                            <Tooltip content="Commit and push to git" position={"bottom"}>
-                                <Button isLoading={isPushing ? true : undefined}
-                                        isSmall
-                                        variant={needCommit ? "primary" : "secondary"}
-                                        className="project-button"
-                                        icon={!isPushing ? <PushIcon/> : <div></div>}
-                                        onClick={() => this.setState({commitMessageIsOpen: true})}>
-                                    {isPushing ? "..." : "Commit"}
-                                </Button>
+                        {isFile && <FlexItem>
+                            <Tooltip content="Download source" position={"bottom-end"}>
+                                <Button isSmall variant="control" icon={<DownloadIcon/>} onClick={e => download()}/>
                             </Tooltip>
-                        </FlexItem>
+                        </FlexItem>}
+                        {!isFile && <FlexItem>
+                            <Button isSmall variant={"secondary"} icon={<PlusIcon/>}
+                                    onClick={e => setCreateModalOpen()}>Create</Button>
+                        </FlexItem>}
+                        {!isFile && <FlexItem>
+                            <Button isSmall variant="secondary" icon={<UploadIcon/>}
+                                    onClick={e => setUploadModalOpen()}>Upload</Button>
+                        </FlexItem>}
                     </Flex>
                 </ToolbarItem>
             </ToolbarContent>
         </Toolbar>
     }
 
-    getProjectToolbar() {
-        const {isPushing, commitMessage} = this.state;
-        const {file, needCommit, mode, editAdvancedProperties, addProperty, setEditAdvancedProperties, download, downloadImage, setCreateModalOpen, setUploadModalOpen} = this.props;
+    function getProjectToolbar() {
+        const {file, mode, editAdvancedProperties,
+            addProperty, setEditAdvancedProperties, download, downloadImage, setCreateModalOpen, setUploadModalOpen} = props;
         const isFile = file !== undefined;
         const isYaml = file !== undefined && file.name.endsWith("yaml");
         const isIntegration = isYaml && file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code);
@@ -116,9 +84,9 @@ export class ProjectPageToolbar extends React.Component<Props> {
                     {isYaml && <FlexItem>
                         <ToggleGroup>
                             <ToggleGroupItem text="Design" buttonId="design" isSelected={mode === "design"}
-                                             onChange={s => this.props.setMode.call(this, "design")}/>
+                                             onChange={s => props.setMode("design")}/>
                             <ToggleGroupItem text="Code" buttonId="code" isSelected={mode === "code"}
-                                             onChange={s => this.props.setMode.call(this, "code")}/>
+                                             onChange={s => props.setMode("code")}/>
                         </ToggleGroup>
                     </FlexItem>}
 
@@ -127,80 +95,41 @@ export class ProjectPageToolbar extends React.Component<Props> {
                             id="advanced"
                             label="Edit advanced"
                             isChecked={editAdvancedProperties}
-                            onChange={checked => setEditAdvancedProperties.call(this, checked)}
+                            onChange={checked => setEditAdvancedProperties(checked)}
                         />
                     </FlexItem>}
                     {isProperties && <FlexItem>
-                        <Button isSmall variant="primary" icon={<PlusIcon/>} onClick={e => addProperty.call(this)}>Add property</Button>
+                        <Button isSmall variant="primary" icon={<PlusIcon/>} onClick={e => addProperty()}>Add property</Button>
                     </FlexItem>}
 
                     {isFile && <FlexItem>
                         <Tooltip content="Download source" position={"bottom-end"}>
-                            <Button isSmall variant="control" icon={<DownloadIcon/>} onClick={e => download.call(this)}/>
+                            <Button isSmall variant="control" icon={<DownloadIcon/>} onClick={e => download()}/>
                         </Tooltip>
                     </FlexItem>}
                     {isIntegration && <FlexItem>
                         <Tooltip content="Download image" position={"bottom-end"}>
-                            <Button isSmall variant="control" icon={<DownloadImageIcon/>} onClick={e => downloadImage.call(this)}/>
+                            <Button isSmall variant="control" icon={<DownloadImageIcon/>} onClick={e => downloadImage()}/>
                         </Tooltip>
                     </FlexItem>}
                     {!isFile && <FlexItem>
                         <Button isSmall variant={"secondary"} icon={<PlusIcon/>}
-                                onClick={e => setCreateModalOpen.call(this)}>Create</Button>
+                                onClick={e => setCreateModalOpen()}>Create</Button>
                     </FlexItem>}
                     {!isFile && <FlexItem>
                         <Button isSmall variant="secondary" icon={<UploadIcon/>}
-                                onClick={e => setUploadModalOpen.call(this)}>Upload</Button>
-                    </FlexItem>}
-                    {!isFile && <FlexItem>
-                        <Tooltip content="Commit and push to git" position={"bottom-end"}>
-                            <Button isLoading={isPushing ? true : undefined}
-                                    isSmall
-                                    variant={needCommit ? "primary" : "secondary"}
-                                    className="project-button"
-                                    icon={!isPushing ? <PushIcon/> : <div></div>}
-                                    onClick={() => this.setState({
-                                        commitMessageIsOpen: true,
-                                        commitMessage : commitMessage === '' ? new Date().toLocaleString() : commitMessage
-                                    })}>
-                                {isPushing ? "..." : "Push"}
-                            </Button>
-                        </Tooltip>
+                                onClick={e => setUploadModalOpen()}>Upload</Button>
                     </FlexItem>}
                 </Flex>
             </ToolbarContent>
         </Toolbar>
     }
 
-    getCommitModal() {
-        let {commitMessage, commitMessageIsOpen} = this.state;
-        return (
-            <Modal
-                title="Commit"
-                variant={ModalVariant.small}
-                isOpen={commitMessageIsOpen}
-                onClose={() => this.setState({commitMessageIsOpen: false})}
-                actions={[
-                    <Button key="confirm" variant="primary" onClick={() => this.push()}>Save</Button>,
-                    <Button key="cancel" variant="secondary" onClick={() => this.setState({commitMessageIsOpen: false})}>Cancel</Button>
-                ]}
-            >
-                <Form autoComplete="off" isHorizontal className="create-file-form">
-                    <FormGroup label="Message" fieldId="name" isRequired>
-                        <TextInput value={commitMessage} onChange={value => this.setState({commitMessage: value})}/>
-                        <FormHelperText isHidden={false} component="div"/>
-                    </FormGroup>
-                </Form>
-            </Modal>
-        )
-    }
-
-    render() {
-        const {isTemplates} = this.props;
-        return <div>
-            {isTemplates && this.getTemplatesToolbar()}
-            {!isTemplates && this.getProjectToolbar()}
-            {this.getCommitModal()}
-        </div>
-    }
+    const {isTemplates} = props;
+    return  (
+         <>
+            {isTemplates && getTemplatesToolbar()}
+            {!isTemplates && getProjectToolbar()}
+        </>
+    )
 }