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 <marat.gubaidul...@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()} + </> + ) }