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 83ab986f070a7ec7a853e07e0fa282ab0d9c88e0
Author: Marat Gubaidullin <marat.gubaidul...@gmail.com>
AuthorDate: Fri Nov 18 21:03:18 2022 -0500

    Templates and Kamelets project panel
---
 .../main/webui/src/projects/ProjectFilesTable.tsx  | 116 +++++++++++++++
 .../src/main/webui/src/projects/ProjectModels.ts   |  13 +-
 .../src/main/webui/src/projects/ProjectPage.tsx    | 165 +++++++--------------
 .../src/main/webui/src/projects/ProjectsPage.tsx   |   1 +
 .../main/webui/src/projects/ProjectsTableRow.tsx   |  32 +---
 5 files changed, 185 insertions(+), 142 deletions(-)

diff --git a/karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx 
b/karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx
new file mode 100644
index 0000000..f1269e4
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx
@@ -0,0 +1,116 @@
+import React from 'react';
+import {
+    Badge,
+    Breadcrumb,
+    BreadcrumbItem,
+    Button,
+    PageSection,
+    Text,
+    TextContent,
+    Bullseye,
+    EmptyState,
+    EmptyStateVariant,
+    EmptyStateIcon,
+    Title,
+    ModalVariant,
+    Modal,
+    Flex,
+    FlexItem,
+    CodeBlockCode,
+    CodeBlock, Skeleton, Tabs, Tab
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {MainToolbar} from "../MainToolbar";
+import {KaravanApi} from "../api/KaravanApi";
+import {getProjectFileType, Project, ProjectFile, ProjectFileTypes} from 
"./ProjectModels";
+import {CamelUi} from "../designer/utils/CamelUi";
+import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
+import {TableComposable, Tbody, Td, Th, Thead, Tr} from 
"@patternfly/react-table";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import {KaravanDesigner} from "../designer/KaravanDesigner";
+import DownloadIcon from 
"@patternfly/react-icons/dist/esm/icons/download-icon";
+import DownloadImageIcon from 
"@patternfly/react-icons/dist/esm/icons/image-icon";
+import FileSaver from "file-saver";
+import Editor from "@monaco-editor/react";
+import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {CreateFileModal} from "./CreateFileModal";
+import {PropertiesEditor} from "./PropertiesEditor";
+import {ProjectModel, ProjectProperty} from 
"karavan-core/lib/model/ProjectModel";
+import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
+import {KubernetesAPI} from "../designer/utils/KubernetesAPI";
+import {UploadModal} from "./UploadModal";
+import {ProjectInfo} from "./ProjectInfo";
+import {ProjectOperations} from "./ProjectOperations";
+import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
+import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
+import {ProjectPageToolbar} from "./ProjectPageToolbar";
+
+interface Props {
+    files: ProjectFile[],
+    onOpenDeleteConfirmation: (file: ProjectFile) => void,
+    onSelect: (file: ProjectFile) => void,
+}
+
+interface State {
+
+}
+
+export class ProjectFilesTable extends React.Component<Props, State> {
+
+    public state: State = {};
+
+    render() {
+        const {files, onOpenDeleteConfirmation, onSelect} = this.props;
+        return (
+            <TableComposable aria-label="Files" variant={"compact"} 
className={"table"}>
+                <Thead>
+                    <Tr>
+                        <Th key='type' width={10}>Type</Th>
+                        <Th key='filename' width={50}>Filename</Th>
+                        <Th key='action'></Th>
+                    </Tr>
+                </Thead>
+                <Tbody>
+                    {files.map(file => {
+                        const type = getProjectFileType(file)
+                        return <Tr key={file.name}>
+                            <Td>
+                                <Badge>{type}</Badge>
+                            </Td>
+                            <Td>
+                                <Button style={{padding: '6px'}} 
variant={"link"}
+                                        onClick={e => onSelect.call(this, 
file)}>
+                                    {file.name}
+                                </Button>
+                            </Td>
+                            <Td modifier={"fitContent"}>
+                                {file.projectId !== 'templates' &&
+                                    <Button style={{padding: '0'}} 
variant={"plain"}
+                                            isDisabled={file.name === 
'application.properties'}
+                                            onClick={e => 
onOpenDeleteConfirmation.call(this, file)}>
+                                        <DeleteIcon/>
+                                    </Button>
+                                }
+                            </Td>
+                        </Tr>
+                    })}
+                    {files.length === 0 &&
+                        <Tr>
+                            <Td colSpan={8}>
+                                <Bullseye>
+                                    <EmptyState 
variant={EmptyStateVariant.small}>
+                                        <EmptyStateIcon icon={SearchIcon}/>
+                                        <Title headingLevel="h2" size="lg">
+                                            No results found
+                                        </Title>
+                                    </EmptyState>
+                                </Bullseye>
+                            </Td>
+                        </Tr>
+                    }
+                </Tbody>
+            </TableComposable>
+        )
+    }
+}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectModels.ts 
b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
index 9e8e522..5764869 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectModels.ts
+++ b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
@@ -98,9 +98,20 @@ export class ProjectFileType {
 
 export const ProjectFileTypes: ProjectFileType[] = [
     new ProjectFileType("INTEGRATION", "Integration", "camel.yaml"),
+    new ProjectFileType("KAMELET", "Kamelet", "kamelet.yaml"),
     new ProjectFileType("CODE", "Code", "java"),
     new ProjectFileType("PROPERTIES", "Properties", "properties"),
     new ProjectFileType("OPENAPI_JSON", "OpenAPI JSON", "json"),
     new ProjectFileType("OPENAPI_YAML", "OpenAPI YAML", "yaml"),
     new ProjectFileType("LOG", "Log", "log"),
-];
\ No newline at end of file
+];
+
+
+export function getProjectFileType (file: ProjectFile) {
+    if (file.name.endsWith(".camel.yaml")) return ProjectFileTypes.filter(p => 
p.name === "INTEGRATION").map(p => p.title)[0];
+    if (file.name.endsWith(".kamelet.yaml")) return ProjectFileTypes.filter(p 
=> p.name === "KAMELET").map(p => p.title)[0];
+    if (file.name.endsWith(".json")) return ProjectFileTypes.filter(p => 
p.name === "OPENAPI_JSON").map(p => p.title)[0];
+    if (file.name.endsWith(".yaml")) return ProjectFileTypes.filter(p => 
p.name === "OPENAPI_YAML").map(p => p.title)[0];
+    const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
+    return ProjectFileTypes.filter(p => p.extension === extension).map(p => 
p.title)[0];
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx 
b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index b748442..8b71766 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -7,11 +7,6 @@ import {
     PageSection,
     Text,
     TextContent,
-    Bullseye,
-    EmptyState,
-    EmptyStateVariant,
-    EmptyStateIcon,
-    Title,
     ModalVariant,
     Modal,
     Flex,
@@ -22,18 +17,10 @@ import {
 import '../designer/karavan.css';
 import {MainToolbar} from "../MainToolbar";
 import {KaravanApi} from "../api/KaravanApi";
-import {Project, ProjectFile, ProjectFileTypes} from "./ProjectModels";
-import {CamelUi} from "../designer/utils/CamelUi";
-import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
-import {TableComposable, Tbody, Td, Th, Thead, Tr} from 
"@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import {getProjectFileType, Project, ProjectFile, ProjectFileTypes} from 
"./ProjectModels";
 import {KaravanDesigner} from "../designer/KaravanDesigner";
-import DownloadIcon from 
"@patternfly/react-icons/dist/esm/icons/download-icon";
-import DownloadImageIcon from 
"@patternfly/react-icons/dist/esm/icons/image-icon";
 import FileSaver from "file-saver";
 import Editor from "@monaco-editor/react";
-import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {CreateFileModal} from "./CreateFileModal";
 import {PropertiesEditor} from "./PropertiesEditor";
 import {ProjectModel, ProjectProperty} from 
"karavan-core/lib/model/ProjectModel";
@@ -43,12 +30,11 @@ import {UploadModal} from "./UploadModal";
 import {ProjectInfo} from "./ProjectInfo";
 import {ProjectOperations} from "./ProjectOperations";
 import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
 import {ProjectPageToolbar} from "./ProjectPageToolbar";
+import {ProjectFilesTable} from "./ProjectFilesTable";
 
 interface Props {
     project: Project,
-    isTemplates?: boolean,
     config: any,
 }
 
@@ -100,7 +86,7 @@ export class ProjectPage extends React.Component<Props, 
State> {
                 this.setState({files: files})
             });
             KubernetesAPI.inKubernetes = true;
-            if (!this.props.isTemplates){
+            if (!this.isBuildIn()){
                 KaravanApi.getConfigMaps(this.state.environment, (any: []) => {
                     KubernetesAPI.setConfigMaps(any);
                 });
@@ -114,6 +100,10 @@ export class ProjectPage extends React.Component<Props, 
State> {
         }
     }
 
+    isBuildIn():boolean {
+        return ['kamelets', 
'templates'].includes(this.props.project.projectId);
+    }
+
     post = (file: ProjectFile) => {
         KaravanApi.postProjectFile(file, res => {
             if (res.status === 200) {
@@ -168,7 +158,7 @@ export class ProjectPage extends React.Component<Props, 
State> {
             project={this.props.project}
             file={this.state.file}
             mode={this.state.mode}
-            isTemplates={this.props.isTemplates}
+            isTemplates={this.isBuildIn()}
             config={this.props.config}
             addProperty={() => this.addProperty()}
             download={() => this.download()}
@@ -180,17 +170,10 @@ export class ProjectPage extends React.Component<Props, 
State> {
             setUploadModalOpen={() => this.setState({isUploadModalOpen: true})}
         />
     }
-
-    getType = (file: ProjectFile) => {
-        if (file.name.endsWith(".camel.yaml")) return 
ProjectFileTypes.filter(p => p.name === "INTEGRATION").map(p => p.title)[0];
-        if (file.name.endsWith(".json")) return ProjectFileTypes.filter(p => 
p.name === "OPENAPI_JSON").map(p => p.title)[0];
-        if (file.name.endsWith(".yaml")) return ProjectFileTypes.filter(p => 
p.name === "OPENAPI_YAML").map(p => p.title)[0];
-        const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
-        return ProjectFileTypes.filter(p => p.extension === extension).map(p 
=> p.title)[0];
-    }
+    
 
     title = () => {
-        const {project, isTemplates} = this.props;
+        const {project} = this.props;
         const file = this.state.file;
         const isFile = file !== undefined;
         const isLog = file !== undefined && file.name.endsWith("log");
@@ -202,7 +185,7 @@ export class ProjectPage extends React.Component<Props, 
State> {
                         <BreadcrumbItem to="#" onClick={event => 
this.setState({file: undefined})}>
                             {"Project: " + project?.projectId}
                         </BreadcrumbItem>
-                        <BreadcrumbItem to="#" 
isActive>{this.getType(file)}</BreadcrumbItem>
+                        <Badge>{getProjectFileType(file)}</Badge>
                     </Breadcrumb>
                     <TextContent className="title">
                         <Text component="h1">{isLog ? filename : 
file.name}</Text>
@@ -210,7 +193,7 @@ export class ProjectPage extends React.Component<Props, 
State> {
                 </div>
             }
             {!isFile && <TextContent className="title">
-                <Text component="h2">{isTemplates ? 'Templates' : 'Project: ' 
+ project?.projectId}</Text>
+                <Text component="h2">{project?.name}</Text>
             </TextContent>}
         </div>)
     };
@@ -243,58 +226,6 @@ export class ProjectPage extends React.Component<Props, 
State> {
         }
     }
 
-    getProjectFiles = () => {
-        const files = this.state.files;
-        return (
-            <TableComposable aria-label="Files" variant={"compact"} 
className={"table"}>
-                <Thead>
-                    <Tr>
-                        <Th key='type' width={10}>Type</Th>
-                        <Th key='filename' width={50}>Filename</Th>
-                        <Th key='action'></Th>
-                    </Tr>
-                </Thead>
-                <Tbody>
-                    {files.map(file => {
-                        const type = this.getType(file)
-                        return <Tr key={file.name}>
-                            <Td>
-                                <Badge>{type}</Badge>
-                            </Td>
-                            <Td>
-                                <Button style={{padding: '6px'}} 
variant={"link"}
-                                        onClick={e => this.select(file)}>
-                                    {file.name}
-                                </Button>
-                            </Td>
-                            <Td modifier={"fitContent"}>
-                                <Button style={{padding: '0'}} 
variant={"plain"}
-                                        isDisabled={file.name === 
'application.properties'}
-                                        onClick={e => 
this.openDeleteConfirmation(file)}>
-                                    <DeleteIcon/>
-                                </Button>
-                            </Td>
-                        </Tr>
-                    })}
-                    {files.length === 0 &&
-                        <Tr>
-                            <Td colSpan={8}>
-                                <Bullseye>
-                                    <EmptyState 
variant={EmptyStateVariant.small}>
-                                        <EmptyStateIcon icon={SearchIcon}/>
-                                        <Title headingLevel="h2" size="lg">
-                                            No results found
-                                        </Title>
-                                    </EmptyState>
-                                </Bullseye>
-                            </Td>
-                        </Tr>
-                    }
-                </Tbody>
-            </TableComposable>
-        )
-    }
-
     getDesigner = () => {
         const file = this.state.file;
         return (
@@ -402,43 +333,50 @@ export class ProjectPage extends React.Component<Props, 
State> {
         )
     }
 
-    getTemplatePanel() {
-        const {tab} = this.state;
+    getProjectPanel() {
+        const isBuildIn = this.isBuildIn();
         return (
             <Flex direction={{default: "column"}} spaceItems={{default: 
"spaceItemsNone"}}>
-                {/*<FlexItem className="project-tabs">*/}
-                {/*    <Tabs activeKey={tab} onSelect={(event, tabIndex) => 
this.setState({tab: tabIndex})}>*/}
-                {/*        <Tab eventKey="templates" title="Templates"/>*/}
-                {/*        <Tab eventKey="kamelets" title="Kamelets"/>*/}
-                {/*    </Tabs>*/}
-                {/*</FlexItem>*/}
-                <FlexItem>
-                    <PageSection padding={{default: "padding"}}>
-                        {this.getProjectFiles()}
-                    </PageSection>
-                </FlexItem>
+                {!isBuildIn && this.getProjectPanelTabs()}
+                {this.getProjectPanelFiles()}
             </Flex>
         )
     }
 
-    getProjectPanel() {
+    getProjectPanelTabs() {
         const {tab} = this.state;
         return (
-            <Flex direction={{default: "column"}} spaceItems={{default: 
"spaceItemsNone"}}>
-                <FlexItem className="project-tabs">
-                    <Tabs activeKey={tab} onSelect={(event, tabIndex) => 
this.setState({tab: tabIndex})}>
-                        <Tab eventKey="development" title="Development"/>
-                        <Tab eventKey="operations" title="Operations"/>
-                    </Tabs>
-                </FlexItem>
-                <FlexItem>
+            <FlexItem className="project-tabs">
+                <Tabs activeKey={tab} onSelect={(event, tabIndex) => 
this.setState({tab: tabIndex})}>
+                    <Tab eventKey="development" title="Development"/>
+                    <Tab eventKey="operations" title="Operations"/>
+                </Tabs>
+            </FlexItem>
+        )
+    }
+
+    getProjectPanelFiles() {
+        const {tab, files} = this.state;
+        const isBuildIn = this.isBuildIn();
+        return (
+            <FlexItem>
+                {isBuildIn &&
+                    <PageSection padding={{default: "padding"}}>
+                        {tab === 'development' && <ProjectFilesTable 
files={files}
+                                                                     
onOpenDeleteConfirmation={this.openDeleteConfirmation}
+                                                                     
onSelect={this.select}/>}
+                    </PageSection>
+                }
+                {!isBuildIn &&
                     <PageSection padding={{default: "padding"}}>
                         {tab === 'development' && <ProjectInfo 
project={this.props.project} config={this.props.config} 
deleteEntity={this.deleteEntity} showLog={this.showLogs}/>}
-                        {tab === 'development' && this.getProjectFiles()}
+                        {tab === 'development' && <ProjectFilesTable 
files={files}
+                                                                     
onOpenDeleteConfirmation={this.openDeleteConfirmation}
+                                                                     
onSelect={this.select}/>}
                         {tab === 'operations' && <ProjectOperations 
environments={this.state.environments} project={this.props.project} 
config={this.props.config}/>}
                     </PageSection>
-                </FlexItem>
-            </Flex>
+                }
+            </FlexItem>
         )
     }
 
@@ -462,23 +400,22 @@ export class ProjectPage extends React.Component<Props, 
State> {
     }
 
     render() {
-        const {isTemplates} = this.props;
-        const {file} = this.state;
+        const {file, isDeleteModalOpen, fileToDelete, isUploadModalOpen, 
isCreateModalOpen} = this.state;
+        const {project} = this.props;
         return (
             <PageSection className="kamelet-section project-page" 
padding={{default: 'noPadding'}}>
                 <PageSection className="tools-section" padding={{default: 
'noPadding'}}>
                     <MainToolbar title={this.title()} tools={this.tools()}/>
                 </PageSection>
-                {file === undefined && isTemplates && this.getTemplatePanel()}
-                {file === undefined && !isTemplates && this.getProjectPanel()}
+                {file === undefined && this.getProjectPanel()}
                 {file !== undefined && this.getFilePanel()}
 
-                <CreateFileModal project={this.props.project} 
isOpen={this.state.isCreateModalOpen}
+                <CreateFileModal project={project} isOpen={isCreateModalOpen}
                                  onClose={this.closeModal}/>
                 <Modal
                     title="Confirmation"
                     variant={ModalVariant.small}
-                    isOpen={this.state.isDeleteModalOpen}
+                    isOpen={isDeleteModalOpen}
                     onClose={() => this.setState({isDeleteModalOpen: false})}
                     actions={[
                         <Button key="confirm" variant="primary" onClick={e => 
this.delete()}>Delete</Button>,
@@ -486,9 +423,9 @@ export class ProjectPage extends React.Component<Props, 
State> {
                                 onClick={e => 
this.setState({isDeleteModalOpen: false})}>Cancel</Button>
                     ]}
                     onEscapePress={e => this.setState({isDeleteModalOpen: 
false})}>
-                    <div>{"Are you sure you want to delete the file " + 
this.state.fileToDelete?.name + "?"}</div>
+                    <div>{"Are you sure you want to delete the file " + 
fileToDelete?.name + "?"}</div>
                 </Modal>
-                <UploadModal projectId={this.props.project.projectId} 
isOpen={this.state.isUploadModalOpen} onClose={this.closeModal}/>
+                <UploadModal projectId={project.projectId} 
isOpen={isUploadModalOpen} onClose={this.closeModal}/>
             </PageSection>
         )
     }
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx 
b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index b3a274e..63f056a 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -278,6 +278,7 @@ export class ProjectsPage extends React.Component<Props, 
State> {
                             config={this.props.config}
                             onSelect={this.props.onSelect}
                             onProjectDelete={this.onProjectDelete}
+                            onProjectCopy={project1 => 
this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project1})}
                             project={project}
                             
deploymentStatuses={this.state.deploymentStatuses}/>
                     ))}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx 
b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
index 86723b5..8b8107a 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
@@ -43,40 +43,18 @@ interface Props {
     config: any,
     onSelect: (project: Project) => void
     onProjectDelete: (project: Project) => void
+    onProjectCopy: (project: Project) => void
     project: Project
     deploymentStatuses: DeploymentStatus[],
 }
 
 interface State {
-    projects: Project[],
-    deploymentStatuses: DeploymentStatus[],
-    isCreateModalOpen: boolean,
-    isDeleteModalOpen: boolean,
-    isCopy: boolean,
-    loading: boolean,
-    projectToCopy?: Project,
-    projectToDelete?: Project,
-    filter: string,
-    name: string,
-    description: string,
-    projectId: string,
-    runtime: string,
+
 }
 
 export class ProjectsTableRow extends React.Component<Props, State> {
 
     public state: State = {
-        projects: [],
-        deploymentStatuses: [],
-        isCreateModalOpen: false,
-        isDeleteModalOpen: false,
-        isCopy: false,
-        loading: true,
-        filter: '',
-        name: '',
-        description: '',
-        projectId: '',
-        runtime: this.props.config.runtime
     };
 
     getEnvironments(): string [] {
@@ -84,7 +62,7 @@ export class ProjectsTableRow extends React.Component<Props, 
State> {
     }
 
     getDeploymentByEnvironments(name: string): [string, DeploymentStatus | 
undefined] [] {
-        const deps = this.state.deploymentStatuses;
+        const deps = this.props.deploymentStatuses;
         return this.getEnvironments().map(e => {
             const env: string = e as string;
             const dep = deps.find(d => d.name === name && d.env === env);
@@ -93,7 +71,7 @@ export class ProjectsTableRow extends React.Component<Props, 
State> {
     }
 
     render() {
-        const {project, onProjectDelete, onSelect} = this.props;
+        const {project, onProjectDelete, onSelect, onProjectCopy} = this.props;
         const isBuildIn = ['kamelets', 
'templates'].includes(project.projectId);
         const badge = isBuildIn ? project.projectId.toUpperCase().charAt(0) : 
project.runtime.substring(0, 1).toUpperCase();
         return (
@@ -134,7 +112,7 @@ export class ProjectsTableRow extends 
React.Component<Props, State> {
                                     <OverflowMenuItem>
                                         <Tooltip content={"Copy project"} 
position={"bottom"}>
                                             <Button variant={"plain"} 
icon={<CopyIcon/>}
-                                                    onClick={e => 
this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: 
project})}></Button>
+                                                    onClick={e => 
onProjectCopy.call(this, project)}></Button>
                                         </Tooltip>
                                     </OverflowMenuItem>
                                     <OverflowMenuItem>

Reply via email to