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 90b8ffb  Saas feature31 (#418)
90b8ffb is described below

commit 90b8ffbec4b5d850049d0d3ca4264f563f067e7c
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Mon Jul 18 09:39:10 2022 -0400

    Saas feature31 (#418)
    
    * Fix environment issues
    
    * Improve Pipeline PVC management
    
    * ImageTag api
    
    * Fix
---
 .../camel/karavan/api/ConfigurationResource.java   |  4 +-
 .../camel/karavan/api/KubernetesResource.java      | 12 +++
 .../apache/camel/karavan/api/StatusResource.java   | 32 +++++++-
 .../camel/karavan/service/GeneratorService.java    |  3 -
 .../camel/karavan/service/InfinispanService.java   |  1 +
 .../camel/karavan/service/KubernetesService.java   | 23 ++++++
 .../camel/karavan/service/StatusService.java       |  3 -
 karavan-app/src/main/webapp/src/api/KaravanApi.tsx |  2 +-
 .../main/webapp/src/projects/ProjectDashboard.tsx  | 90 +++++++++-------------
 .../src/main/webapp/src/projects/ProjectHeader.tsx | 54 -------------
 .../src/main/webapp/src/projects/ProjectInfo.tsx   | 14 +++-
 .../src/main/webapp/src/projects/ProjectPage.tsx   | 30 +++++---
 .../src/main/webapp/src/projects/ProjectsPage.tsx  |  2 +-
 karavan-builder/README.md                          |  6 ++
 karavan-builder/openshift/karavan-acl.yaml         | 31 +++-----
 .../openshift/karavan-act-environments.yaml        | 13 ++++
 .../openshift/karavan-quarkus-pipeline.yaml        |  8 ++
 .../openshift/karavan-quarkus-task.yaml            | 20 ++---
 karavan-builder/openshift/kustomization.yaml       |  1 -
 19 files changed, 182 insertions(+), 167 deletions(-)

diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
index b2f23ef..04f6f75 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
@@ -44,7 +44,9 @@ public class ConfigurationResource {
         return Response.ok(
                 Map.of(
                         "version", version,
-                        "environments", 
configuration.environments().stream().map(e -> 
e.name()).collect(Collectors.toList()),
+                        "environments", configuration.environments().stream()
+                                        .filter(e -> e.active())
+                                .map(e -> 
e.name()).collect(Collectors.toList()),
                         "runtime", configuration.runtime()
                 )
         ).build();
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index b97c1e6..1a0476f 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -33,6 +33,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.List;
 import java.util.Optional;
 
 @Path("/kubernetes")
@@ -140,6 +141,17 @@ public class KubernetesResource {
         return Response.noContent().build();
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/imagetag/{environment}/{projectId}")
+    public Response getProjectImageTags(@HeaderParam("username") String 
username, @PathParam("environment") String environment, @PathParam("projectId") 
String projectId) throws Exception {
+        Optional<KaravanConfiguration.Environment> env = 
configuration.environments().stream().filter(e -> 
e.name().equals(environment)).findFirst();
+        if (env.isPresent()) {
+            return 
Response.ok(kubernetesService.getProjectImageTags(projectId, 
env.get().namespace())).build();
+        }
+        return Response.noContent().build();
+    }
+
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/configmap/{environment}")
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
index 5bc23b4..054730a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
@@ -31,6 +31,8 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Path("/status")
@@ -49,8 +51,8 @@ public class StatusResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/{projectId}")
-    public ProjectStatus getStatus(@HeaderParam("username") String username, 
@PathParam("projectId") String projectId) throws Exception {
+    @Path("/project/{projectId}")
+    public ProjectStatus getStatus(@HeaderParam("username") String username, 
@PathParam("projectId") String projectId) {
         bus.publish(StatusService.CMD_COLLECT_STATUSES, projectId);
         ProjectStatus status = infinispanService.getProjectStatus(projectId);
         if (status != null){
@@ -63,4 +65,30 @@ public class StatusResource {
                     Long.valueOf(0));
         }
     }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/projects")
+    public Map<String, Map> getSimpleStatus(@HeaderParam("username") String 
username) throws Exception {
+        Map<String, Map> result = new HashMap<>();
+        infinispanService.getProjects().forEach(project -> {
+            ProjectStatus ps = getStatus(username, project.getProjectId());
+            Map<String, String> statuses = new HashMap<>();
+            ps.getStatuses().forEach(pes -> {
+                if (pes.getLastPipelineRunResult() == null || 
pes.getDeploymentStatus() == null || pes.getContextStatus() == null){
+                    statuses.put(pes.getEnvironment(), "N/A");
+                } else {
+                    boolean pipelineOK = 
pes.getLastPipelineRunResult().equals("Succeeded");
+                    System.out.println(pes.getLastPipelineRunResult());
+                    boolean deploymentOK = 
pes.getDeploymentStatus().getReadyReplicas() == 
pes.getDeploymentStatus().getReplicas() && 
pes.getDeploymentStatus().getUnavailableReplicas() == 0;
+                    boolean camelOK = 
pes.getContextStatus().equals(ProjectEnvStatus.Status.UP) && 
pes.getConsumerStatus().equals(ProjectEnvStatus.Status.UP) && 
pes.getRoutesStatus().equals(ProjectEnvStatus.Status.UP);
+                    String status = (pipelineOK && deploymentOK && camelOK) ? 
"UP" : "DOWN";
+                    statuses.put(pes.getEnvironment(), status);
+                }
+            });
+            result.put(project.getProjectId(), statuses);
+        });
+
+        return result;
+    }
 }
\ No newline at end of file
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
index 220cb6a..ffcae12 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
@@ -69,9 +69,6 @@ public class GeneratorService {
                 
.append("mvn:io.quarkus:quarkus-openshift").append(System.lineSeparator());
 
         s.append("camel.health.enabled=true").append(System.lineSeparator());
-        
s.append("camel.health.routes-enabled=true").append(System.lineSeparator());
-        
s.append("camel.health.consumers-enabled=true").append(System.lineSeparator());
-        
s.append("camel.health.registry-enabled=true").append(System.lineSeparator());
         
s.append("camel.health.exposure-level=full").append(System.lineSeparator());
 
         
s.append("quarkus.container-image.group=").append(imageGroup).append(System.lineSeparator());
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
index 1cdcbad..ed42868 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
@@ -34,6 +34,7 @@ import 
org.infinispan.commons.configuration.XMLStringConfiguration;
 import org.infinispan.configuration.cache.CacheMode;
 import org.infinispan.configuration.cache.ConfigurationBuilder;
 import org.infinispan.configuration.cache.SingleFileStoreConfigurationBuilder;
+import org.infinispan.configuration.cache.StorageType;
 import org.infinispan.configuration.global.GlobalConfigurationBuilder;
 import org.infinispan.manager.DefaultCacheManager;
 import org.infinispan.query.dsl.QueryFactory;
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index a75b4c8..4e76a63 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -23,6 +23,7 @@ import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.client.DefaultKubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.openshift.api.model.DeploymentConfig;
+import io.fabric8.openshift.api.model.ImageStream;
 import io.fabric8.openshift.client.OpenShiftClient;
 import io.fabric8.tekton.client.DefaultTektonClient;
 import io.fabric8.tekton.pipeline.v1beta1.ParamBuilder;
@@ -32,6 +33,7 @@ import io.fabric8.tekton.pipeline.v1beta1.PipelineRun;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunBuilder;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunSpec;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunSpecBuilder;
+import io.fabric8.tekton.pipeline.v1beta1.WorkspaceBindingBuilder;
 import org.apache.camel.karavan.model.DeploymentStatus;
 import org.apache.camel.karavan.model.PipelineRunLog;
 import org.apache.camel.karavan.model.PodStatus;
@@ -42,6 +44,7 @@ import org.jboss.logging.Logger;
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.inject.Produces;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -90,6 +93,9 @@ public class KubernetesService {
                 .withPipelineRef(ref)
                 .withServiceAccountName("pipeline")
                 .withParams(new 
ParamBuilder().withName("PROJECT_NAME").withNewValue(project.getProjectId()).build())
+                .withWorkspaces(
+                        new 
WorkspaceBindingBuilder().withName("m2-cache").withNewPersistentVolumeClaim("karavan-m2-cache",
 false).build(),
+                        new 
WorkspaceBindingBuilder().withName("jbang-cache").withNewPersistentVolumeClaim("karavan-jbang-cache",
 false).build())
                 .build();
 
         PipelineRunBuilder pipelineRunBuilder = new PipelineRunBuilder()
@@ -241,6 +247,23 @@ public class KubernetesService {
         return result;
     }
 
+    public List<String> getProjectImageTags (String projectId, String 
namespace){
+        List<String> result = new ArrayList<>();
+        try {
+            if (kubernetesClient().isAdaptable(OpenShiftClient.class)) {
+                ImageStream is = 
openshiftClient().imageStreams().inNamespace(namespace).withName(projectId).get();
+                if (is != null) {
+                    result.addAll(is.getSpec().getTags().stream().map(t -> 
t.getName()).sorted(Comparator.reverseOrder()).collect(Collectors.toList()));
+                }
+            } else {
+                // TODO: Implement for Kubernetes/Minikube
+            }
+        } catch (Exception ex) {
+            LOGGER.error(ex.getMessage());
+        }
+        return result;
+    }
+
     public Secret getKaravanSecret() {
         return 
kubernetesClient().secrets().inNamespace(currentNamespace).withName("karavan").get();
     }
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
index cf8ca70..a07889f 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
@@ -79,7 +79,6 @@ public class StatusService {
     }
 
     private void getStatuses(String projectId) throws Exception {
-        LOGGER.info("Start to collect statuses for the project " + projectId);
         ProjectStatus old = infinispanService.getProjectStatus(projectId);
         ProjectStatus status = new ProjectStatus();
         status.setProjectId(projectId);
@@ -109,8 +108,6 @@ public class StatusService {
             statuses.add(pes);
         });
         status.setStatuses(statuses);
-
-        LOGGER.info("Storing status in cache for " + projectId);
         infinispanService.saveProjectStatus(status);
     }
 
diff --git a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx 
b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
index a1146bd..7a2e172 100644
--- a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
@@ -28,7 +28,7 @@ export const KaravanApi = {
     },
 
     getProjectStatus: async (projectId: string, after: (status: ProjectStatus) 
=> void) => {
-        axios.get('/status/' + projectId,
+        axios.get('/status/project/' + projectId,
             {headers: {'Accept': 'application/json', 'username': 'cameleer'}})
             .then(res => {
                 if (res.status === 200) {
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx 
b/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
index 40e7b6c..96b9ea5 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
@@ -7,8 +7,8 @@ import {
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import {KaravanApi} from "../api/KaravanApi";
-import {Project, ProjectFileTypes, ProjectStatus} from 
"../models/ProjectModels";
-import {ChartDonut} from "@patternfly/react-charts";
+import {Project, ProjectEnvStatus, ProjectFileTypes, ProjectStatus} from 
"../models/ProjectModels";
+import {ChartDonut, ChartDonutThreshold, ChartDonutUtilization} from 
"@patternfly/react-charts";
 
 interface Props {
     project: Project,
@@ -19,7 +19,6 @@ interface Props {
 interface State {
     project?: Project,
     status?: ProjectStatus,
-
     key?: string,
 }
 
@@ -71,32 +70,6 @@ export class ProjectDashboard extends React.Component<Props, 
State> {
         }
     }
 
-    getCurrentStatus() {
-        return (<Text>OK</Text>)
-    }
-
-    // getPipelineState() {
-    //     const {project, status} = this.state;
-    //     const isRunning = status?.pipeline === 'Running';
-    //     const isFailed = status?.pipeline === 'Failed';
-    //     const isSucceeded = status?.pipeline === 'Succeeded';
-    //     let classname = "pipeline"
-    //     if (isRunning) classname = classname + " pipeline-running";
-    //     if (isFailed) classname = classname + " pipeline-running";
-    //     if (isSucceeded) classname = classname + " pipeline-succeeded";
-    //     return (
-    //         <Flex spaceItems={{default: 'spaceItemsNone'}} 
className={classname} direction={{default: "row"}}
-    //               alignItems={{default: "alignItemsCenter"}}>
-    //             <FlexItem style={{height: "18px"}}>
-    //                 {isRunning && <Spinner isSVG diameter="16px"/>}
-    //             </FlexItem>
-    //             <FlexItem style={{height: "18px"}}>
-    //                 {project?.lastPipelineRun ? project?.lastPipelineRun : 
"-"}
-    //             </FlexItem>
-    //         </Flex>
-    //     )
-    // }
-
     isUp(env: string): boolean {
         if (this.state.status) {
             return this.state.status.statuses.find(s => s.environment === 
env)?.status === 'UP';
@@ -105,30 +78,39 @@ export class ProjectDashboard extends 
React.Component<Props, State> {
         }
     }
 
-    getEnvironmentData() {
-        const used  = true;
-        const replicas = 3;
-        const data = Array.from({length: replicas}, (v, k) => {
-            return { x: k, y: 100/replicas }
-        });
-        const readyReplicas = 2;
-        const colorScale = Array.from({length: replicas}, (v, k) => {
-            console.log(" " + k)
-            if (k < readyReplicas) return "rgb(56, 129, 47)"
-            else return "#8bc1f7"
-        })
-        return (
-            <div style={{ height: '130px', width: '130px' }}>
-                <ChartDonut
-                    constrainToVisibleArea={true}
-                    data={data}
-                    colorScale={colorScale}
-                    labels={({ datum }) => datum.x ? datum.x : null}
-                    title="Pods"
-                >
-                </ChartDonut>
-            </div>
-        );
+    getEnvironmentData(env: string) {
+        const pes  = this.state.status?.statuses.find(s => s.environment == 
env);
+        if (pes){
+            const replicas = pes.deploymentStatus.replicas;
+            const data = Array.from({length: replicas}, (v, k) => {
+                return { x: k, y: 100/replicas }
+            });
+            const unavailableReplicas = 
pes.deploymentStatus.unavailableReplicas;
+            const dataU = Array.from({length: unavailableReplicas}, (v, k) => {
+                return { x: k, y: 100/unavailableReplicas }
+            });
+            const readyReplicas = pes.deploymentStatus.readyReplicas;
+            const colorScale = Array.from({length: replicas}, (v, k) => {
+                if (k < readyReplicas) return "rgb(56, 129, 47)"
+                else return "#8bc1f7"
+            })
+            return (
+                <div style={{ height: '185px', width: '185px' }}>
+                    <ChartDonutThreshold
+                        constrainToVisibleArea
+                        data={data}
+                        colorScale={colorScale}
+                        height={185}
+                        width={185}
+                    >
+                        <ChartDonutThreshold
+                            data={dataU}
+                            title="Pods"
+                        />
+                    </ChartDonutThreshold>
+                </div>
+            );
+        }
     }
 
     render() {
@@ -145,7 +127,7 @@ export class ProjectDashboard extends 
React.Component<Props, State> {
                                             <Badge className={this.isUp(e) ? 
"badge-env-up" : ""} isRead>{e}</Badge>
                                         </FlexItem>
                                         <FlexItem>
-                                            {this.getEnvironmentData()}
+                                            {this.getEnvironmentData(e)}
                                         </FlexItem>
                                     </Flex>
                                 </CardBody>
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx 
b/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx
deleted file mode 100644
index 29880f9..0000000
--- a/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from 'react';
-import {
-    Flex,
-    FlexItem,
-    Tabs,
-    Tab,
-    PageSection,
-} from '@patternfly/react-core';
-import '../designer/karavan.css';
-import {Project, ProjectStatus} from "../models/ProjectModels";
-import {ProjectDashboard} from "./ProjectDashboard";
-import {ProjectInfo} from "./ProjectInfo";
-
-interface Props {
-    project: Project,
-    config: any,
-    environments: string [],
-    showLog: (type: 'container' | 'pipeline', name: string, environment: 
string) => void
-    deleteEntity: (type: 'pod' | 'deployment', name: string, environment: 
string) => void
-}
-
-interface State {
-    project?: Project,
-    status?: ProjectStatus,
-    tab: string | number;
-}
-
-export class ProjectHeader extends React.Component<Props, State> {
-
-    public state: State = {
-        project: this.props.project,
-        tab: "details"
-    };
-
-    render() {
-        const {tab} = this.state;
-        return (
-            <Flex direction={{default: "column"}} spaceItems={{default: 
"spaceItemsNone"}}>
-                <FlexItem>
-                    <Tabs activeKey={tab} onSelect={(event, tabIndex) => 
this.setState({tab: tabIndex})}>
-                        <Tab eventKey="details" title="Details"/>
-                        <Tab eventKey="dashboard" title="Dashboard"/>
-                    </Tabs>
-                </FlexItem>
-                <FlexItem>
-                    <PageSection padding={{default: "padding"}}>
-                        {tab === 'details' && <ProjectInfo 
project={this.props.project} config={this.props.config} 
deleteEntity={this.props.deleteEntity} showLog={this.props.showLog}/>}
-                        {tab === 'dashboard' && <ProjectDashboard 
environments={this.props.environments} project={this.props.project} 
config={this.props.config}/>}
-                    </PageSection>
-                </FlexItem>
-            </Flex>
-        )
-    }
-}
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx 
b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
index cbc4820..ce726a5 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
@@ -2,7 +2,6 @@ import React from 'react';
 import {
     Badge,
     Button,
-    Text,
     DescriptionList,
     DescriptionListTerm,
     DescriptionListGroup,
@@ -141,10 +140,17 @@ export class ProjectInfo extends React.Component<Props, 
State> {
         </Tooltip>)
     }
 
-    buildButton = () => {
+    buildButton = (env: string) => {
         const isDeploying = this.state.isBuilding;
+        const isPushing = this.state.isPushing;
+        const status = this.state.status?.statuses.find(s => s.environment === 
env)
+        const pipelineResult = status?.lastPipelineRunResult;
+        const isRunning = pipelineResult === 'Running';
         return (<Tooltip content="Commit, push, build and deploy" 
position={"left"}>
-            <Button isLoading={isDeploying ? true : undefined} isSmall 
variant="secondary"
+            <Button isLoading={isDeploying ? true : undefined}
+                    isDisabled={isDeploying || isRunning || isPushing}
+                    isSmall
+                    variant="secondary"
                     className="project-button"
                     icon={!isDeploying ? <BuildIcon/> : <div></div>}
                     onClick={e => {
@@ -347,7 +353,7 @@ export class ProjectInfo extends React.Component<Props, 
State> {
                         </LabelGroup>
                     </Tooltip>
                 </FlexItem>
-                <FlexItem>{env === "dev" && this.buildButton()}</FlexItem>
+                <FlexItem>{env === "dev" && this.buildButton(env)}</FlexItem>
             </Flex>
         )
     }
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx 
b/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
index 631434c..a96ca7f 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
@@ -21,7 +21,7 @@ import {
     ToggleGroup,
     ToggleGroupItem,
     CodeBlockCode,
-    CodeBlock, Skeleton, Switch, Checkbox
+    CodeBlock, Skeleton, Switch, Checkbox, Tabs, Tab
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import {MainToolbar} from "../MainToolbar";
@@ -39,11 +39,12 @@ 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 {ProjectHeader} from "./ProjectHeader";
 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 {ProjectDashboard} from "./ProjectDashboard";
 
 interface Props {
     project: Project,
@@ -64,6 +65,7 @@ interface State {
     key: string
     environments: string[],
     environment: string,
+    tab: string | number;
 }
 
 export class ProjectPage extends React.Component<Props, State> {
@@ -77,6 +79,7 @@ export class ProjectPage extends React.Component<Props, 
State> {
         mode: "design",
         editAdvancedProperties: false,
         key: '',
+        tab: "details",
         environments: this.props.config.environments && 
Array.isArray(this.props.config.environments)
             ? Array.from(this.props.config.environments) : [],
         environment: this.props.config.environments && 
Array.isArray(this.props.config.environments)
@@ -421,7 +424,7 @@ export class ProjectPage extends React.Component<Props, 
State> {
     }
 
     render() {
-        const {file, mode} = this.state;
+        const {file, mode, tab} = this.state;
         const isYaml = file !== undefined && file.name.endsWith("yaml");
         const isProperties = file !== undefined && 
file.name.endsWith("properties");
         const isLog = file !== undefined && file.name.endsWith("log");
@@ -436,12 +439,21 @@ export class ProjectPage extends React.Component<Props, 
State> {
                 {file === undefined &&
                     <PageSection isFilled className="kamelets-page 
project-page-section"
                                  padding={{default: file !== undefined ? 
'noPadding' : 'noPadding'}}>
-                        {<ProjectHeader project={this.props.project}
-                                        config={this.props.config}
-                                        environments={this.state.environments}
-                                        showLog={this.showPipelineLog}
-                                        deleteEntity={this.deleteEntity}/>}
-                        {this.getProjectFiles()}
+                        <Flex direction={{default: "column"}} 
spaceItems={{default: "spaceItemsNone"}}>
+                            <FlexItem>
+                                <Tabs activeKey={tab} onSelect={(event, 
tabIndex) => this.setState({tab: tabIndex})}>
+                                    <Tab eventKey="details" title="Details"/>
+                                    <Tab eventKey="dashboard" 
title="Dashboard"/>
+                                </Tabs>
+                            </FlexItem>
+                            <FlexItem>
+                                <PageSection padding={{default: "padding"}}>
+                                    {tab === 'details' && <ProjectInfo 
project={this.props.project} config={this.props.config} 
deleteEntity={this.deleteEntity} showLog={this.showPipelineLog}/>}
+                                    {tab === 'dashboard' && <ProjectDashboard 
environments={this.state.environments} project={this.props.project} 
config={this.props.config}/>}
+                                </PageSection>
+                            </FlexItem>
+                        </Flex>
+                        {tab === 'details' && this.getProjectFiles()}
                     </PageSection>}
                 {showDesigner && this.getDesigner()}
                 {showEditor && this.getEditor()}
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx 
b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
index 1e0d65a..3c32227 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
@@ -166,7 +166,7 @@ export class ProjectsPage extends React.Component<Props, 
State> {
                                 <Th key='name'>Name</Th>
                                 <Th key='description'>Description</Th>
                                 <Th key='commit'>Commit</Th>
-                                <Th key='deployment'>Deployment</Th>
+                                <Th key='deployment'>Environment</Th>
                                 <Th key='action'></Th>
                             </Tr>
                         </Thead>
diff --git a/karavan-builder/README.md b/karavan-builder/README.md
index b782152..638573a 100644
--- a/karavan-builder/README.md
+++ b/karavan-builder/README.md
@@ -2,3 +2,9 @@
 ```
 docker build -t apache/camel-karavan-builder .
 ```
+
+### To deploy to test and prod from karavan namespace
+```
+oc policy add-role-to-user system:image-puller 
system:serviceaccount:test:default --namespace=karavan
+oc policy add-role-to-user system:image-puller 
system:serviceaccount:prod:default --namespace=karavan
+```
diff --git a/karavan-builder/openshift/karavan-acl.yaml 
b/karavan-builder/openshift/karavan-acl.yaml
index 7670950..eb86382 100644
--- a/karavan-builder/openshift/karavan-acl.yaml
+++ b/karavan-builder/openshift/karavan-acl.yaml
@@ -13,28 +13,15 @@ kind: Role
 metadata:
   name: karavan-app
 rules:
-  - apiGroups:
-      - ""
-    resources:
-      - secrets
-      - configmaps
-    verbs:
-      - get
-      - list
-  - apiGroups:
-      - ""
-      - apps.openshift.io
-    resources:
-      - deploymentconfigs
-      - replicationcontrollers
-    verbs:
-      - create
-      - delete
-      - get
-      - list
-      - patch
-      - update
-      - watch
+  - apiGroups: [""]
+    resources: ["secrets", "configmaps"]
+    verbs: ["get", "list"]
+  - apiGroups: [""]
+    resources: ["persistentvolumes", "persistentvolumeclaims"]
+    verbs: ["*"]
+  - apiGroups: ["", "apps.openshift.io"]
+    resources: ["deploymentconfigs", "replicationcontrollers"]
+    verbs: ["*"]
 ---
 # Role tekton run pipeline
 kind: Role
diff --git a/karavan-builder/openshift/karavan-act-environments.yaml 
b/karavan-builder/openshift/karavan-act-environments.yaml
new file mode 100644
index 0000000..737d51a
--- /dev/null
+++ b/karavan-builder/openshift/karavan-act-environments.yaml
@@ -0,0 +1,13 @@
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: karavan-image-puller-test
+  namespace: karavan
+subjects:
+  - kind: ServiceAccount
+    name: default
+    namespace: test
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: 'system:image-puller'
\ No newline at end of file
diff --git a/karavan-builder/openshift/karavan-quarkus-pipeline.yaml 
b/karavan-builder/openshift/karavan-quarkus-pipeline.yaml
index fa15bc7..20b2710 100644
--- a/karavan-builder/openshift/karavan-quarkus-pipeline.yaml
+++ b/karavan-builder/openshift/karavan-quarkus-pipeline.yaml
@@ -14,3 +14,11 @@ spec:
       taskRef:
         kind: Task
         name: karavan-quarkus-builder
+      workspaces:
+        - name: m2-cache
+          workspace: m2-cache
+        - name: jbang-cache
+          workspace: jbang-cache  
+  workspaces:
+    - name: m2-cache
+    - name: jbang-cache
\ No newline at end of file
diff --git a/karavan-builder/openshift/karavan-quarkus-task.yaml 
b/karavan-builder/openshift/karavan-quarkus-task.yaml
index 5d39b42..1acfe14 100644
--- a/karavan-builder/openshift/karavan-quarkus-task.yaml
+++ b/karavan-builder/openshift/karavan-quarkus-task.yaml
@@ -12,6 +12,9 @@ spec:
           #!/usr/bin/env bash
           CHECKOUT_DIR="/scripts"
 
+          ls -la $(workspaces.m2-cache.path)
+          ls -la $(workspaces.jbang-cache.path)
+
           if  [[ $GIT_REPOSITORY == https* ]] ;
           then
               replacer=https://$GIT_PASSWORD@
@@ -45,11 +48,6 @@ spec:
             -Dquarkus.container-image.group=${NAMESPACE} \
             -Dquarkus.container-image.tag=${DATE}
       image: 'ghcr.io/apache/camel-karavan-builder:0.0.16'
-      volumeMounts:
-        - mountPath: /root/.m2
-          name: m2-cache
-        - mountPath: /jbang/.jbang/cache
-          name: jbang-cache  
       env:
         - name: GIT_REPOSITORY
           valueFrom:
@@ -73,10 +71,8 @@ spec:
         #!/usr/bin/env bash
         oc label dc/$(inputs.params.project) app.openshift.io/runtime=camel 
--overwrite=true
         oc rollout latest dc/$(inputs.params.project) 
-  volumes:
-    - name: m2-cache
-      persistentVolumeClaim:
-        claimName: karavan-m2-cache 
-    - name: jbang-cache
-      persistentVolumeClaim:
-        claimName: karavan-jbang-cache
+  workspaces:
+    - mountPath: /root/.m2
+      name: m2-cache
+    - mountPath: /jbang/.jbang/cache
+      name: jbang-cache     
\ No newline at end of file
diff --git a/karavan-builder/openshift/kustomization.yaml 
b/karavan-builder/openshift/kustomization.yaml
index ddd4e52..b046577 100644
--- a/karavan-builder/openshift/kustomization.yaml
+++ b/karavan-builder/openshift/kustomization.yaml
@@ -2,7 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 
 resources:
-- pipeline-operator.yaml
 - karavan-namespace.yaml
 - karavan-acl.yaml
 - karavan-pvc.yaml

Reply via email to