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/08/19 16:47:36 UTC

[camel-karavan] branch main updated: Fix #867

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


The following commit(s) were added to refs/heads/main by this push:
     new 936d91a9 Fix #867
936d91a9 is described below

commit 936d91a9b47f595649bf67e8d4df3fde9c3efc0a
Author: Marat Gubaidullin <ma...@Marats-MacBook-Pro.local>
AuthorDate: Sat Aug 19 12:47:28 2023 -0400

    Fix #867
---
 .../src/main/webui/src/api/ProjectModels.ts        |   8 +-
 .../karavan-app/src/main/webui/src/main/Main.tsx   |   2 +
 .../src/main/webui/src/main/PageNavigation.tsx     |   2 +
 .../src/main/webui/src/project/ProjectPage.tsx     |   2 +-
 .../src/main/webui/src/project/ProjectPanel.tsx    |   6 +-
 .../src/main/webui/src/project/ProjectToolbar.tsx  |  12 ++-
 .../src/main/webui/src/project/files/FilesTab.tsx  |   8 +-
 .../main/webui/src/project/files/FilesToolbar.tsx  |  16 +--
 .../src/main/webui/src/projects/ProjectsPage.tsx   |  14 +--
 .../main/webui/src/projects/ProjectsTableRow.tsx   |   1 -
 .../webui/src/templates/CreateProjectModal.tsx     | 118 +++++++++++++++++++++
 .../webui/src/templates/DeleteProjectModal.tsx     |  53 +++++++++
 .../TemplatesPage.tsx}                             |  32 ++----
 .../TemplatesTableRow.tsx}                         |  47 +-------
 14 files changed, 219 insertions(+), 102 deletions(-)

diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
index 763f2f76..d8056c37 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
@@ -136,8 +136,8 @@ export const ProjectFileTypes: ProjectFileType[] = [
     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("JSON", "JSON", "json"),
+    new ProjectFileType("YAML", "YAML", "yaml"),
     new ProjectFileType("LOG", "Log", "log"),
 ];
 
@@ -145,8 +145,8 @@ export const ProjectFileTypes: ProjectFileType[] = [
 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];
+    if (file.name.endsWith(".json")) return ProjectFileTypes.filter(p => p.name === "JSON").map(p => p.title)[0];
+    if (file.name.endsWith(".yaml")) return ProjectFileTypes.filter(p => p.name === "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];
 }
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
index 7a3fa986..c03b0026 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
@@ -19,6 +19,7 @@ import {PageNavigation} from "./PageNavigation";
 import {Notification} from "./Notification";
 import {useMainHook} from "./useMainHook";
 import {MainDataPoller} from "./MainDataPoller";
+import {TemplatesPage} from "../templates/TemplatesPage";
 
 export const Main = () => {
 
@@ -75,6 +76,7 @@ export const Main = () => {
                             <Route path="/dashboard" element={<DashboardPage key={'dashboard'}/>}/>
                             <Route path="/projects" element={<ProjectsPage key={'projects'}/>}/>
                             <Route path="/projects/:projectId" element={<ProjectPage key={'project'}/>}/>
+                            <Route path="/templates" element={<TemplatesPage key={'templates'}/>}/>
                             <Route path="/services" element={<ServicesPage key="services"/>}/>
                             <Route path="/containers" element={<ContainersPage key="services"/>}/>
                             <Route path="/knowledgebase" element={<KnowledgebasePage dark={false}/>}/>
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx b/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
index 2c35c44b..0d47461b 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
@@ -11,6 +11,7 @@ import '../designer/karavan.css';
 import Icon from "../Logo";
 import UserIcon from "@patternfly/react-icons/dist/js/icons/user-icon";
 import ProjectsIcon from "@patternfly/react-icons/dist/js/icons/repository-icon";
+import TemplatesIcon from "@patternfly/react-icons/dist/js/icons/blueprint-icon";
 import KnowledgebaseIcon from "@patternfly/react-icons/dist/js/icons/book-open-icon";
 import ContainersIcon from "@patternfly/react-icons/dist/js/icons/cubes-icon";
 import DashboardIcon from "@patternfly/react-icons/dist/js/icons/tachometer-alt-icon";
@@ -44,6 +45,7 @@ export const PageNavigation = () => {
         const pages: MenuItem[] = [
             new MenuItem("dashboard", "Dashboard", <DashboardIcon/>),
             new MenuItem("projects", "Projects", <ProjectsIcon/>),
+            new MenuItem("templates", "Templates", <TemplatesIcon/>),
         ]
         if (config.infrastructure === 'docker') {
             pages.push(
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index a771570c..53e4f81b 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -35,7 +35,7 @@ export const ProjectPage = () => {
     }, []);
 
     function isBuildIn(): boolean {
-        return ['kamelets', 'templates'].includes(project.projectId);
+        return ['kamelets', 'templates', 'services'].includes(project.projectId);
     }
 
     function isKameletsProject(): boolean {
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 ae163a41..feed11e7 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
@@ -26,16 +26,14 @@ export const ProjectPanel = () => {
     }
 
     function isBuildIn(): boolean {
-        return ['kamelets', 'templates'].includes(project.projectId);
+        return ['kamelets', 'templates', 'services'].includes(project.projectId);
     }
 
     const buildIn = isBuildIn();
+    const isCustomKamelets = project.projectId === 'kamelets';
     return (
         <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
             <FlexItem className="project-tabs">
-                {buildIn && <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}>
-                    <Tab eventKey="files" title="Files"/>
-                </Tabs>}
                 {!buildIn && <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}>
                     <Tab eventKey="files" title="Files"/>
                     <Tab eventKey="dashboard" title="Dashboard"/>
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 07ed9373..fd2e0ebc 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
@@ -73,7 +73,7 @@ export const ProjectToolbar = () => {
             <ToolbarContent>
                 <Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}>
                     {isRunnable() && <DevModeToolbar reloadOnly={true}/>}
-                    {isYaml() && <FlexItem>
+                    {isIntegration() && <FlexItem>
                         <ToggleGroup>
                             <ToggleGroupItem text="Design" buttonId="design" isSelected={mode === "design"}
                                              onChange={(_event, s) => setMode("design")}/>
@@ -120,8 +120,16 @@ export const ProjectToolbar = () => {
         return project.projectId === 'templates';
     }
 
+    function isServicesProject(): boolean {
+        return project.projectId === 'services';
+    }
+
     function isRunnable(): boolean {
-        return !isKameletsProject() && !isTemplatesProject();
+        return !isKameletsProject() && !isTemplatesProject() && !isServicesProject();
+    }
+
+    function allowAddFiles(): boolean {
+        return !isTemplatesProject() && !isServicesProject();
     }
 
     const isTemplates = isTemplatesProject();
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
index 12218265..19e90617 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
@@ -58,7 +58,11 @@ export const FilesTab = () => {
     }
 
     function isBuildIn(): boolean {
-        return ['kamelets', 'templates'].includes(project.projectId);
+        return ['kamelets', 'templates', 'services'].includes(project.projectId);
+    }
+
+    function canDeleteFiles(): boolean {
+        return !['templates', 'services'].includes(project.projectId);
     }
 
     function isKameletsProject(): boolean {
@@ -109,7 +113,7 @@ export const FilesTab = () => {
                                 {!needCommit(file.lastUpdate) && getDate(file.lastUpdate)}
                             </Td>
                             <Td modifier={"fitContent"}>
-                                {file.projectId !== 'templates' &&
+                                {canDeleteFiles() &&
                                     <Button style={{padding: '0'}} variant={"plain"}
                                             isDisabled={file.name === 'application.properties'}
                                             onClick={e =>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
index a5ee8418..6dc19421 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
@@ -46,6 +46,10 @@ export const FileToolbar = () => {
         ProjectService.pushProject(project, commitMessage);
     }
 
+    function canAddFiles(): boolean {
+        return !['templates', 'services'].includes(project.projectId);
+    }
+
     function getCommitModal() {
         return (
             <Modal
@@ -121,14 +125,14 @@ export const FileToolbar = () => {
                 </Button>
             </Tooltip>
         </FlexItem>
-        <FlexItem>
+        {canAddFiles() && <FlexItem>
             <Button size="sm" variant={"secondary"} icon={<PlusIcon/>}
-                    onClick={e => useFileStore.setState({operation:"create"})}>Create</Button>
-        </FlexItem>
-        <FlexItem>
+                    onClick={e => useFileStore.setState({operation: "create"})}>Create</Button>
+        </FlexItem>}
+        {canAddFiles() && <FlexItem>
             <Button size="sm" variant="secondary" icon={<UploadIcon/>}
-                    onClick={e => useFileStore.setState({operation:"upload"})}>Upload</Button>
-        </FlexItem>
+                    onClick={e => useFileStore.setState({operation: "upload"})}>Upload</Button>
+        </FlexItem>}
         {getCommitModal()}
     </Flex>
 }
diff --git a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index ef49c8aa..aca27ffd 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from 'react';
+import React, {useState} from 'react';
 import {
     Toolbar,
     ToolbarContent,
@@ -11,11 +11,9 @@ import {
     Bullseye,
     EmptyState,
     EmptyStateVariant,
-    EmptyStateIcon,
-    Spinner, EmptyStateHeader, Flex, FlexItem
+    EmptyStateIcon, EmptyStateHeader
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
-import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
 import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
 import {
     Tbody,
@@ -32,17 +30,9 @@ import {ProjectsTableRow} from "./ProjectsTableRow";
 import {DeleteProjectModal} from "./DeleteProjectModal";
 import {CreateProjectModal} from "./CreateProjectModal";
 import {useProjectsStore, useProjectStore} from "../api/ProjectStore";
-import {ProjectService} from "../api/ProjectService";
 import {MainToolbar} from "../designer/MainToolbar";
 import {Project, ProjectType} from "../api/ProjectModels";
 import {shallow} from "zustand/shallow";
-import {PageNavigation} from "../main/PageNavigation";
-import {DashboardPage} from "../dashboard/DashboardPage";
-import {ProjectPage} from "../project/ProjectPage";
-import {ServicesPage} from "../services/ServicesPage";
-import {ContainersPage} from "../containers/ContainersPage";
-import {KnowledgebasePage} from "../knowledgebase/KnowledgebasePage";
-
 
 export const ProjectsPage = () => {
 
diff --git a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
index 6dfa00b7..f23c0206 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
@@ -15,7 +15,6 @@ import {
     useLogStore,
     useProjectStore, useStatusesStore,
 } from "../api/ProjectStore";
-import {ProjectEventBus} from "../api/ProjectEventBus";
 import {shallow} from "zustand/shallow";
 import {CamelIcon, QuarkusIcon, SpringIcon} from "../designer/utils/KaravanIcons";
 import {useNavigate} from "react-router-dom";
diff --git a/karavan-web/karavan-app/src/main/webui/src/templates/CreateProjectModal.tsx b/karavan-web/karavan-app/src/main/webui/src/templates/CreateProjectModal.tsx
new file mode 100644
index 00000000..0d7c1be1
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/src/templates/CreateProjectModal.tsx
@@ -0,0 +1,118 @@
+import React, {useState} from 'react';
+import {
+    Button, Form, FormGroup, FormHelperText, HelperText, HelperTextItem,
+    Modal,
+    ModalVariant, TextInput, ToggleGroup, ToggleGroupItem,
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {useAppConfigStore, useProjectStore} from "../api/ProjectStore";
+import {ProjectService} from "../api/ProjectService";
+import {Project} from "../api/ProjectModels";
+import {QuarkusIcon, SpringIcon, CamelIcon} from "../designer/utils/KaravanIcons";
+import {CamelUi} from "../designer/utils/CamelUi";
+
+
+export const CreateProjectModal = () => {
+
+    const {project, operation} = useProjectStore();
+    const [name, setName] = useState('');
+    const [description, setDescription] = useState('');
+    const [projectId, setProjectId] = useState('');
+    const {config} = useAppConfigStore();
+    const [runtime, setRuntime] = useState(config.runtime);
+
+    function cleanValues() {
+        setName("");
+        setDescription("");
+        setRuntime(config.runtime);
+        setProjectId("");
+    }
+
+    function closeModal() {
+        useProjectStore.setState({operation: "none"});
+        cleanValues();
+    }
+
+    function confirmAndCloseModal() {
+        ProjectService.createProject(new Project({name: name, description: description, runtime: runtime, projectId: projectId}));
+        useProjectStore.setState({operation: "none"});
+        cleanValues();
+    }
+
+    function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {
+        if (event.key === 'Enter' && name !== undefined && description !== undefined && projectId !== undefined) {
+            confirmAndCloseModal();
+        }
+    }
+
+    function getIcon(runtime: string) {
+        if (runtime === 'quarkus') return QuarkusIcon();
+        else if (runtime === 'spring-boot') return SpringIcon();
+        else if (runtime === 'camel-main') return CamelIcon();
+    }
+
+    function getTitle(runtime: string) {
+        if (runtime === 'quarkus') return "Quarkus";
+        else if (runtime === 'spring-boot') return "Spring";
+        else if (runtime === 'camel-main') return "Camel";
+    }
+
+    const runtimes = config.runtimes;
+    const defaultRuntime = config.runtime;
+    const isReady = projectId && name && description && !['templates', 'kamelets'].includes(projectId);
+    return (
+        <Modal
+            title={operation !== 'copy' ? "Create new project" : "Copy project from " + project?.projectId}
+            variant={ModalVariant.small}
+            isOpen={["create", "copy"].includes(operation)}
+            onClose={closeModal}
+            onKeyDown={onKeyDown}
+            actions={[
+                <Button key="confirm" variant="primary" isDisabled={!isReady}
+                        onClick={confirmAndCloseModal}>Save</Button>,
+                <Button key="cancel" variant="secondary" onClick={closeModal}>Cancel</Button>
+            ]}
+            className="new-project"
+        >
+            <Form isHorizontal={true} autoComplete="off">
+                <FormGroup label="Name" fieldId="name" isRequired>
+                    <TextInput className="text-field" type="text" id="name" name="name"
+                               value={name}
+                               onChange={(_, e) => setName(e)}/>
+                </FormGroup>
+                <FormGroup label="Description" fieldId="description" isRequired>
+                    <TextInput className="text-field" type="text" id="description" name="description"
+                               value={description}
+                               onChange={(_, e) => setDescription(e)}/>
+                </FormGroup>
+                <FormGroup label="Project ID" fieldId="projectId" isRequired>
+                    <TextInput className="text-field" type="text" id="projectId" name="projectId"
+                               value={projectId}
+                               onFocus={e => setProjectId(projectId === '' ? CamelUi.nameFromTitle(name) : projectId)}
+                               onChange={(_, e) => setProjectId(CamelUi.nameFromTitle(e))}/>
+                    <FormHelperText>
+                        <HelperText>
+                            <HelperTextItem>Unique project name</HelperTextItem>
+                        </HelperText>
+                    </FormHelperText>
+                </FormGroup>
+                <FormGroup label="Runtime" fieldId="runtime" isRequired>
+                    <ToggleGroup>
+                        {runtimes?.map((r: string) => (
+                            <ToggleGroupItem key={r} id={r} name={r}
+                                             aria-label="runtime"
+                                             isSelected={r === runtime}
+                                             text={getTitle(r)}
+                                             icon={getIcon(r)}
+                                              onChange={(_, checked) => {
+                                                 if (checked) setRuntime(r)
+                                             }}
+                            />
+                        ))}
+                    </ToggleGroup>
+                </FormGroup>
+            </Form>
+        </Modal>
+    )
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/templates/DeleteProjectModal.tsx b/karavan-web/karavan-app/src/main/webui/src/templates/DeleteProjectModal.tsx
new file mode 100644
index 00000000..5ae29dd4
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/src/templates/DeleteProjectModal.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import {
+    Button,
+    Modal,
+    ModalVariant,
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {useProjectStore} from "../api/ProjectStore";
+import {ProjectService} from "../api/ProjectService";
+
+export const DeleteProjectModal = () => {
+
+    const {project, operation} = useProjectStore();
+
+    function closeModal () {
+        useProjectStore.setState({operation: "none"})
+    }
+
+    function confirmAndCloseModal () {
+        ProjectService.deleteProject(project);
+        useProjectStore.setState({operation: "none"});
+    }
+
+    const isOpen= operation === "delete";
+    return (
+            <Modal
+                title="Confirmation"
+                variant={ModalVariant.small}
+                isOpen={isOpen}
+                onClose={() => closeModal()}
+                actions={[
+                    <Button key="confirm" variant="primary" onClick={e => confirmAndCloseModal()}>Delete</Button>,
+                    <Button key="cancel" variant="link"
+                            onClick={e => closeModal()}>Cancel</Button>
+                ]}
+                onEscapePress={e => closeModal()}>
+                <div>{"Are you sure you want to delete the project " + project?.projectId + "?"}</div>
+            </Modal>
+            // }
+            // {(this.state.isProjectDeploymentModalOpen === true) && <Modal
+            //     variant={ModalVariant.small}
+            //     isOpen={this.state.isProjectDeploymentModalOpen}
+            //     onClose={() => this.setState({ isProjectDeploymentModalOpen: false })}
+            //     onEscapePress={e => this.setState({ isProjectDeploymentModalOpen: false })}>
+            //     <div>
+            //         <Alert key={this.state.projectToDelete?.projectId} className="main-alert" variant="warning"
+            //                title={"Deployment is Running!!"} isInline={true} isPlain={true}>
+            //             {"Delete the deployment (" + this.state.projectToDelete?.projectId + ")" + " first."}
+            //         </Alert>
+            //     </div>
+            // </Modal>
+    )
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
similarity index 74%
copy from karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
copy to karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
index ef49c8aa..130eb2ee 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from 'react';
+import React, {useState} from 'react';
 import {
     Toolbar,
     ToolbarContent,
@@ -12,10 +12,9 @@ import {
     EmptyState,
     EmptyStateVariant,
     EmptyStateIcon,
-    Spinner, EmptyStateHeader, Flex, FlexItem
+    EmptyStateHeader
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
-import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
 import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
 import {
     Tbody,
@@ -28,23 +27,15 @@ import {
     Table
 } from '@patternfly/react-table/deprecated';
 import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
-import {ProjectsTableRow} from "./ProjectsTableRow";
+import {TemplatesTableRow} from "./TemplatesTableRow";
 import {DeleteProjectModal} from "./DeleteProjectModal";
 import {CreateProjectModal} from "./CreateProjectModal";
 import {useProjectsStore, useProjectStore} from "../api/ProjectStore";
-import {ProjectService} from "../api/ProjectService";
 import {MainToolbar} from "../designer/MainToolbar";
 import {Project, ProjectType} from "../api/ProjectModels";
 import {shallow} from "zustand/shallow";
-import {PageNavigation} from "../main/PageNavigation";
-import {DashboardPage} from "../dashboard/DashboardPage";
-import {ProjectPage} from "../project/ProjectPage";
-import {ServicesPage} from "../services/ServicesPage";
-import {ContainersPage} from "../containers/ContainersPage";
-import {KnowledgebasePage} from "../knowledgebase/KnowledgebasePage";
 
-
-export const ProjectsPage = () => {
+export const TemplatesPage = () => {
 
     const [projects] = useProjectsStore((state) => [state.projects], shallow)
     const [operation] = useProjectStore((state) => [state.operation], shallow)
@@ -59,12 +50,6 @@ export const ProjectsPage = () => {
                                value={filter}
                                onChange={(_, e) => setFilter(e)}/>
                 </ToolbarItem>
-                <ToolbarItem>
-                    <Button icon={<PlusIcon/>}
-                            onClick={e =>
-                                useProjectStore.setState({operation: "create", project: new Project()})}
-                    >Create</Button>
-                </ToolbarItem>
             </ToolbarContent>
         </Toolbar>
     }
@@ -92,24 +77,21 @@ export const ProjectsPage = () => {
 
     function getProjectsTable() {
         const projs = projects
-            .filter(p => p.type === ProjectType.normal)
+            .filter(p => p.type !== ProjectType.normal)
             .filter(p => p.name.toLowerCase().includes(filter) || p.description.toLowerCase().includes(filter));
         return (
-            <Table aria-label="Projects" variant={"compact"}>
+            <Table aria-label="Templates" variant={"compact"}>
                 <Thead>
                     <Tr>
-                        <Th key='type'>Runtime</Th>
                         <Th key='projectId'>Project ID</Th>
                         <Th key='name'>Name</Th>
                         <Th key='description'>Description</Th>
                         <Th key='commit'>Commit</Th>
-                        <Th key='deployment'>Environment</Th>
-                        <Th key='action'></Th>
                     </Tr>
                 </Thead>
                 <Tbody>
                     {projs.map(project => (
-                        <ProjectsTableRow
+                        <TemplatesTableRow
                             key={project.projectId}
                             project={project}/>
                     ))}
diff --git a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesTableRow.tsx
similarity index 55%
copy from karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
copy to karavan-web/karavan-app/src/main/webui/src/templates/TemplatesTableRow.tsx
index 6dfa00b7..9b9b0ada 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesTableRow.tsx
@@ -3,19 +3,15 @@ import {
     Button,
     Badge,
     Tooltip,
-    Flex, FlexItem, Label
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import { Td, Tr} from "@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
-import CopyIcon from "@patternfly/react-icons/dist/esm/icons/copy-icon";
 import {Project} from '../api/ProjectModels';
 import {
     useAppConfigStore,
     useLogStore,
     useProjectStore, useStatusesStore,
 } from "../api/ProjectStore";
-import {ProjectEventBus} from "../api/ProjectEventBus";
 import {shallow} from "zustand/shallow";
 import {CamelIcon, QuarkusIcon, SpringIcon} from "../designer/utils/KaravanIcons";
 import {useNavigate} from "react-router-dom";
@@ -24,7 +20,7 @@ interface Props {
     project: Project
 }
 
-export const ProjectsTableRow = (props: Props) => {
+export const TemplatesTableRow = (props: Props) => {
 
     const [deployments, containers] = useStatusesStore((state) => [state.deployments, state.containers], shallow)
     const {config} = useAppConfigStore();
@@ -58,9 +54,6 @@ export const ProjectsTableRow = (props: Props) => {
     const commit = project.lastCommit ? project.lastCommit?.substr(0, 7) : "...";
     return (
         <Tr key={project.projectId}>
-            <Td className="icon-td">
-                {getIcon(project.runtime)}
-            </Td>
             <Td>
                 <Button style={{padding: '6px'}} variant={"link"} onClick={e => {
                     // setProject(project, "select");
@@ -73,47 +66,11 @@ export const ProjectsTableRow = (props: Props) => {
             </Td>
             <Td>{project.name}</Td>
             <Td>{project.description}</Td>
-            <Td isActionCell>
+            <Td>
                 <Tooltip content={project.lastCommit} position={"bottom"}>
                     <Badge className="badge">{commit}</Badge>
                 </Tooltip>
             </Td>
-            <Td noPadding style={{width: "180px"}}>
-                {!isBuildIn &&
-                    <Flex direction={{default: "row"}}>
-                        {getStatusByEnvironments(project.projectId).map(value => {
-                            const active = value[1];
-                            const color = active ? "green" : "grey"
-                            const style = active ? {fontWeight: "bold"} : {}
-                            return <FlexItem className="badge-flex-item" key={value[0]}>
-                                <Label style={style} color={color} >{value[0]}</Label>
-                            </FlexItem>
-                        })}
-                    </Flex>
-                }
-            </Td>
-            <Td className="project-action-buttons">
-                {!isBuildIn &&
-                    <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}}
-                          spaceItems={{default: 'spaceItemsNone'}}>
-                        <FlexItem>
-                            <Tooltip content={"Copy project"} position={"bottom"}>
-                                <Button variant={"plain"} icon={<CopyIcon/>}
-                                        onClick={e => {
-                                            setProject(project, "copy");
-                                        }}></Button>
-                            </Tooltip>
-                        </FlexItem>
-                        <FlexItem>
-                            <Tooltip content={"Delete project"} position={"bottom"}>
-                                <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => {
-                                    setProject(project, "delete");
-                                }}></Button>
-                            </Tooltip>
-                        </FlexItem>
-                    </Flex>
-                }
-            </Td>
         </Tr>
     )
 }
\ No newline at end of file