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/12/27 17:12:27 UTC

(camel-karavan) branch main updated: Fix #951

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 adac8323 Fix #951
adac8323 is described below

commit adac832308195e5bd8364ee5238c7474f3e51c7d
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Wed Dec 27 12:12:20 2023 -0500

    Fix #951
---
 .../apache/camel/karavan/api/ProjectResource.java  |  25 ++++-
 .../src/main/webui/src/api/KaravanApi.tsx          |   5 +-
 .../src/main/webui/src/api/ProjectService.ts       |   4 +-
 .../main/webui/src/projects/DeleteProjectModal.tsx |  30 ++---
 .../webui/src/templates/CreateProjectModal.tsx     | 122 ---------------------
 .../webui/src/templates/DeleteProjectModal.tsx     |  70 ------------
 .../src/main/webui/src/templates/TemplatesPage.tsx |   9 +-
 7 files changed, 39 insertions(+), 226 deletions(-)

diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
index 6acc57f5..29541520 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
@@ -25,6 +25,7 @@ import org.apache.camel.karavan.git.GitService;
 import org.apache.camel.karavan.infinispan.InfinispanService;
 import org.apache.camel.karavan.infinispan.model.CamelStatus;
 import org.apache.camel.karavan.infinispan.model.CamelStatusValue;
+import org.apache.camel.karavan.infinispan.model.ContainerStatus;
 import org.apache.camel.karavan.infinispan.model.Project;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
 import org.apache.camel.karavan.service.ConfigService;
@@ -53,6 +54,15 @@ public class ProjectResource {
     @Inject
     GitService gitService;
 
+    @Inject
+    DevModeResource devModeResource;
+
+    @Inject
+    ContainerResource containerResource;
+
+    @Inject
+    InfrastructureResource infrastructureResource;
+
     @Inject
     ProjectService projectService;
 
@@ -88,12 +98,20 @@ public class ProjectResource {
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/{project}")
-    public void delete(@HeaderParam("username") String username,
-                          @PathParam("project") String project) throws Exception {
+    public void delete(@PathParam("project") String project, @QueryParam("deleteContainers") boolean deleteContainers) throws Exception {
         String projectId = URLDecoder.decode(project, StandardCharsets.UTF_8);
+        if (deleteContainers) {
+            LOGGER.info("Deleting containers");
+            Response res1 = devModeResource.deleteDevMode(projectId, true);
+            Response res2 = containerResource.deleteContainer(projectId, ContainerStatus.ContainerType.devmode.name(), projectId);
+            Response res3 = containerResource.deleteContainer(projectId, ContainerStatus.ContainerType.project.name(), projectId);
+            LOGGER.info("Deleting deployments");
+            Response res4 = infrastructureResource.deleteDeployment(null, projectId);
+        }
         gitService.deleteProject(projectId, infinispanService.getProjectFiles(projectId));
         infinispanService.getProjectFiles(projectId).forEach(file -> infinispanService.deleteProjectFile(projectId, file.getName()));
         infinispanService.deleteProject(projectId);
+        LOGGER.info("Project deleted");
     }
 
     @POST
@@ -113,8 +131,7 @@ public class ProjectResource {
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/build/{env}/{buildName}")
-    public Response deleteBuild(@HeaderParam("username") String username,
-                       @PathParam("env") String env, @PathParam("buildName") String buildName) {
+    public Response deleteBuild(@PathParam("env") String env, @PathParam("buildName") String buildName) {
         buildName = URLDecoder.decode(buildName, StandardCharsets.UTF_8);
         if (ConfigService.inKubernetes()) {
             kubernetesService.deletePod(buildName);
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 0d07f0da..70d34a60 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -254,9 +254,8 @@ export class KaravanApi {
             });
     }
 
-    static async deleteProject(project: Project, after: (res: AxiosResponse<any>) => void) {
-        instance.delete('/api/project/' + encodeURI(project.projectId),
-            {headers: {'username': 'cameleer'}})
+    static async deleteProject(project: Project, deleteContainers: boolean, after: (res: AxiosResponse<any>) => void) {
+        instance.delete('/api/project/' + encodeURI(project.projectId) + (deleteContainers ? '?deleteContainers=true' : ''))
             .then(res => {
                 after(res);
             }).catch(err => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
index 9f64e7f0..6f567937 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
@@ -225,8 +225,8 @@ export class ProjectService {
         });
     }
 
-    public static deleteProject(project: Project) {
-        KaravanApi.deleteProject(project, res => {
+    public static deleteProject(project: Project, deleteContainers?: boolean) {
+        KaravanApi.deleteProject(project, deleteContainers === true, res => {
             if (res.status === 204) {
                 EventBus.sendAlert( 'Success', 'Project deleted', 'success');
                 ProjectService.refreshProjects();
diff --git a/karavan-web/karavan-app/src/main/webui/src/projects/DeleteProjectModal.tsx b/karavan-web/karavan-app/src/main/webui/src/projects/DeleteProjectModal.tsx
index 02bda7b1..574486cb 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/DeleteProjectModal.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/projects/DeleteProjectModal.tsx
@@ -15,11 +15,11 @@
  * limitations under the License.
  */
 
-import React from 'react';
+import React, {useState} from 'react';
 import {
     Button,
     Modal,
-    ModalVariant,
+    ModalVariant, Switch,
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import {useProjectStore} from "../api/ProjectStore";
@@ -28,20 +28,21 @@ import {ProjectService} from "../api/ProjectService";
 export function DeleteProjectModal () {
 
     const {project, operation} = useProjectStore();
+    const [deleteContainers, setDeleteContainers] = useState(false);
 
     function closeModal () {
         useProjectStore.setState({operation: "none"})
     }
 
     function confirmAndCloseModal () {
-        ProjectService.deleteProject(project);
+        ProjectService.deleteProject(project, deleteContainers);
         useProjectStore.setState({operation: "none"});
     }
 
     const isOpen= operation === "delete";
     return (
             <Modal
-                title="Confirmation"
+                title="Project delete confirmation"
                 variant={ModalVariant.small}
                 isOpen={isOpen}
                 onClose={() => closeModal()}
@@ -51,20 +52,13 @@ export function DeleteProjectModal () {
                             onClick={e => closeModal()}>Cancel</Button>
                 ]}
                 onEscapePress={e => closeModal()}>
-                <div>{"Are you sure you want to delete the project " + project?.projectId + "?"}</div>
+                {/*<div>{"Are you sure you want to delete the project " + project?.projectId + "?"}</div>*/}
+                <Switch
+                    label={"Delete container and/or deployments?"}
+                    isChecked={deleteContainers}
+                    onChange={(_, checked) => setDeleteContainers(checked)}
+                    isReversed
+                />
             </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/templates/CreateProjectModal.tsx b/karavan-web/karavan-app/src/main/webui/src/templates/CreateProjectModal.tsx
deleted file mode 100644
index b6300be9..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/templates/CreateProjectModal.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import React, {useState} from 'react';
-import {
-    Button, Form, FormGroup, FormHelperText, HelperText, HelperTextItem,
-    Modal,
-    ModalVariant, TextInput, Text
-} from '@patternfly/react-core';
-import '../designer/karavan.css';
-import {useProjectStore} from "../api/ProjectStore";
-import {ProjectService} from "../api/ProjectService";
-import {Project} from "../api/ProjectModels";
-import {CamelUi} from "../designer/utils/CamelUi";
-import {EventBus} from "../designer/utils/EventBus";
-import {ProjectExistsError} from "../shared/error/ProjectExistsError";
-
-
-export function CreateProjectModal () {
-
-    const {project, operation} = useProjectStore();
-    const [name, setName] = useState('');
-    const [description, setDescription] = useState('');
-    const [projectId, setProjectId] = useState('');
-    const [isValidationError, setIsValidationError] = useState(false);
-
-    function cleanValues() {
-        setName("");
-        setDescription("");
-        setProjectId("");
-    }
-
-    function closeModal() {
-        useProjectStore.setState({operation: "none"});
-        cleanValues();
-    }
-
-    async function handleFormSubmit() {
-        setIsValidationError(false);
-        const [ err, createdProject ] = operation !== 'copy' ?
-            await ProjectService.createProject(new Project({name: name, description: description, projectId: projectId})) :
-            await ProjectService.copyProject(project?.projectId, new Project({name: name, description: description, projectId: projectId}));
-
-        if (createdProject !== null) {
-            EventBus.sendAlert( 'Success', 'Project created', 'success');
-            ProjectService.refreshProjectData(project.projectId);
-            ProjectService.refreshProjects();
-            useProjectStore.setState({operation: "none"});
-            cleanValues();
-        } else if (err !== null && err instanceof ProjectExistsError) {
-            setIsValidationError(true);
-        } else {
-            operation !== 'copy' ?
-                EventBus.sendAlert( 'Warning', 'Error when creating project:' + err?.message, 'warning') :
-                EventBus.sendAlert( 'Warning', 'Error when copying project:' + err?.message, 'warning');
-        }
-    }
-
-    function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {
-        if (event.key === 'Enter' && name !== undefined && description !== undefined && projectId !== undefined) {
-            handleFormSubmit();
-        }
-    }
-
-    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={handleFormSubmit}>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))}
-                               validated={isValidationError ? 'error' : 'default'}
-                    />
-                    {isValidationError && <Text  style={{ color: 'red', fontStyle: 'italic'}}>Project ID must be unique</Text>}
-                    <FormHelperText>
-                        <HelperText>
-                            <HelperTextItem>Unique project name</HelperTextItem>
-                        </HelperText>
-                    </FormHelperText>
-                </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
deleted file mode 100644
index 02bda7b1..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/templates/DeleteProjectModal.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-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 function 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/templates/TemplatesPage.tsx b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
index ee6c7063..96588eab 100644
--- a/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
@@ -45,17 +45,14 @@ import {
 } from '@patternfly/react-table/deprecated';
 import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
 import {TemplatesTableRow} from "./TemplatesTableRow";
-import {DeleteProjectModal} from "./DeleteProjectModal";
-import {CreateProjectModal} from "./CreateProjectModal";
-import {useProjectsStore, useProjectStore} from "../api/ProjectStore";
+import {useProjectsStore} from "../api/ProjectStore";
 import {MainToolbar} from "../designer/MainToolbar";
-import {Project, ProjectType} from "../api/ProjectModels";
+import {ProjectType} from "../api/ProjectModels";
 import {shallow} from "zustand/shallow";
 
 export function TemplatesPage () {
 
     const [projects] = useProjectsStore((state) => [state.projects], shallow)
-    const [operation] = useProjectStore((state) => [state.operation], shallow)
     const [filter, setFilter] = useState<string>('');
 
     function getTools() {
@@ -126,8 +123,6 @@ export function TemplatesPage () {
             <PageSection isFilled className="kamelets-page">
                 {getProjectsTable()}
             </PageSection>
-            {["create", "copy"].includes(operation) && <CreateProjectModal/>}
-            {["delete"].includes(operation) && <DeleteProjectModal/>}
         </PageSection>
 
     )