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 9c68c36 Fixed login Openshift/Kubernetes (#341)
9c68c36 is described below
commit 9c68c36729cca062f0b1739e306293029ed441f0
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Fri May 13 14:13:48 2022 -0400
Fixed login Openshift/Kubernetes (#341)
---
karavan-core/src/core/api/ProjectModelApi.ts | 19 +++--
karavan-core/src/core/model/ProjectModel.ts | 45 ++++++++++--
karavan-core/test/application.spec.ts | 6 +-
.../postman-openshift/application.properties | 25 +++----
karavan-designer/src/App.tsx | 5 +-
karavan-designer/src/builder/BuilderPage.tsx | 83 ++++++++++++++++-----
karavan-vscode/src/builderView.ts | 28 ++++----
karavan-vscode/src/commands.ts | 5 +-
karavan-vscode/webview/builder/BuilderPage.tsx | 84 +++++++++++++++++-----
.../webview/components/ComponentCard.tsx | 2 +-
.../webview/components/ComponentModal.tsx | 4 +-
karavan-vscode/webview/eip/EipCard.tsx | 2 +-
karavan-vscode/webview/eip/EipModal.tsx | 2 +-
karavan-vscode/webview/kamelets/KameletCard.tsx | 2 +-
karavan-vscode/webview/kamelets/KameletModal.tsx | 3 +-
15 files changed, 228 insertions(+), 87 deletions(-)
diff --git a/karavan-core/src/core/api/ProjectModelApi.ts
b/karavan-core/src/core/api/ProjectModelApi.ts
index 93001ed..77a3b6e 100644
--- a/karavan-core/src/core/api/ProjectModelApi.ts
+++ b/karavan-core/src/core/api/ProjectModelApi.ts
@@ -30,17 +30,19 @@ export class ProjectModelApi {
project.version = this.getValue(map, "project.version");
project.namespace = this.getValue(map, "project.namespace");
project.cleanup = this.getValue(map, "project.cleanup") === "true";
- const tag = this.getValue(map, "build.image.tag", "deploy.image");
- project.tag = tag ? tag : project.namespace + "/" + project.name + ":"
+ project.version;
+ const image = this.getValue(map, "build.image.image", "deploy.image");
+ project.image = image ? image : project.namespace + "/" + project.name
+ ":" + project.version;
project.classpathFiles = this.getValue(map, "classpathFiles");
project.routesIncludePattern = this.getValue(map,
"routesIncludePattern");
project.sourceImage = this.getValue(map, "build.image.source-image");
project.from = this.getValue(map, "build.image.from");
+ project.buildConfig = this.getValue(map, "build.image.build-config")
=== "true";
project.filename = this.getValue(map, "build.image.jar",
"package.uber-jar.jar");
project.replicas = this.getValue(map, "deploy.replicas");
project.nodePort = this.getValue(map, "deploy.node-port");
project.server = this.getValue(map, "deploy.server",
"build.image.server");
+ project.username = this.getValue(map, "deploy.username",
"build.image.username");
const openshift = this.getValue(map, "deploy.openshift",
"build.image.openshift") === "true";
const minikube = this.getValue(map, "deploy.minikube",
"build.image.minikube") === "true";
project.target = openshift ? "openshift" : (minikube ? "minikube" :
"kubernetes");
@@ -95,7 +97,7 @@ export class ProjectModelApi {
static projectToMap = (project: ProjectModel): Map<string, any> => {
const map = new Map<string, any>();
- if (project.tag?.length === 0) project.tag = project.namespace + "/" +
project.name + ":" + project.version;
+ if (project.image?.length === 0) project.image = project.namespace +
"/" + project.name + ":" + project.version;
this.setValue(map, "project.name", project.name);
this.setValue(map, "project.version", project.version);
this.setValue(map, "project.namespace", project.namespace);
@@ -107,19 +109,22 @@ export class ProjectModelApi {
this.setValue(map, "routesIncludePattern",
project.routesIncludePattern);
this.setValue(map, "build.image", project.build);
this.setValue(map, "build.image.openshift", project.target ===
'openshift');
- this.setValue(map, "build.image.minikube", project.target ===
'minikube');
+ this.setValue(map, "build.image.build-config", project.buildConfig);
+ this.setValue(map, "build.image.push", project.target === 'openshift'
&& !project.buildConfig);
this.setValue(map, "build.image.jar", project.filename);
- this.setValue(map, "build.image.tag", project.tag);
+ this.setValue(map, "build.image.image", project.image);
this.setValue(map, "build.image.source-image", project.sourceImage);
this.setValue(map, "build.image.from", project.from);
this.setValue(map, "build.image.server", project.server);
+ this.setValue(map, "build.image.username", project.username);
this.setValue(map, "deploy", project.deploy);
this.setValue(map, "deploy.openshift", project.target === 'openshift');
this.setValue(map, "deploy.minikube", project.target === 'minikube');
- this.setValue(map, "deploy.image", project.tag);
+ this.setValue(map, "deploy.image", project.image);
this.setValue(map, "deploy.replicas", project.replicas);
this.setValue(map, "deploy.node-port", project.nodePort);
this.setValue(map, "deploy.server", project.server);
+ this.setValue(map, "deploy.username", project.username);
this.setValue(map, "undeploy.openshift", project.target ===
'openshift');
this.setValue(map, "undeploy.minikube", project.target === 'minikube');
this.setValue(map, "undeploy.server", project.server);
@@ -127,7 +132,7 @@ export class ProjectModelApi {
this.setValue(map, "manifests.path", project.manifests);
this.setValue(map, "manifests.openshift", project.target ===
'openshift');
this.setValue(map, "manifests.minikube", project.target ===
'minikube');
- this.setValue(map, "manifests.image", project.tag);
+ this.setValue(map, "manifests.image", project.image);
this.setValue(map, "manifests.replicas", project.replicas);
this.setValue(map, "manifests.node-port", project.nodePort);
this.setValue(map, "manifests.server", project.server);
diff --git a/karavan-core/src/core/model/ProjectModel.ts
b/karavan-core/src/core/model/ProjectModel.ts
index 6340e6d..9def742 100644
--- a/karavan-core/src/core/model/ProjectModel.ts
+++ b/karavan-core/src/core/model/ProjectModel.ts
@@ -15,14 +15,45 @@
* limitations under the License.
*/
-export class ProjectStatus {
- uberJar: 'pending' | 'progress' | 'done' | 'error' = 'pending';
- build: 'pending' | 'progress' | 'done' | 'error' = 'pending';
- deploy: 'pending' | 'progress' | 'done'| 'error' = 'pending';
- undeploy: 'pending' | 'progress' | 'done'| 'error' = 'pending';
+export class StepStatus {
+ status: 'pending' | 'progress' | 'done' | 'error' = 'pending';
+ startTime: number = Date.now();
+ endTime?: number;
+
+ public constructor(init?: Partial<StepStatus>) {
+ Object.assign(this, init);
+ }
+
+ static progress(): StepStatus {
+ return new StepStatus({status: "progress", startTime: Date.now()})
+ }
+
+ static done(stepStatus?: StepStatus): StepStatus | undefined {
+ if (stepStatus){
+ stepStatus.status = "done";
+ stepStatus.endTime = Date.now();
+ }
+ return stepStatus
+ }
+
+ static error(stepStatus?: StepStatus): StepStatus | undefined {
+ if (stepStatus) {
+ stepStatus.status = "error";
+ stepStatus.endTime = Date.now();
+ }
+ return stepStatus
+ }
+}
+
+export class ProjectStatus extends StepStatus{
+ uberJar?: StepStatus;
+ build?: StepStatus;
+ deploy?: StepStatus;
+ undeploy?: StepStatus;
active: boolean = false;
public constructor(init?: Partial<ProjectStatus>) {
+ super();
Object.assign(this, init);
}
}
@@ -33,12 +64,14 @@ export class ProjectModel {
filename: string = 'camel-runner.jar'
namespace: string = 'default'
cleanup: boolean = false
- tag?: string = this.namespace + "/" + this.name + ":" + this.version
+ image?: string = this.namespace + "/" + this.name + ":" + this.version
sourceImage: string = 'java:openjdk-11-ubi8'
from: string = 'gcr.io/distroless/java:11'
replicas: number = 1
nodePort: number = 30777
server?: string
+ username?: string
+ password?: string
token?: string
target: 'openshift' | 'minikube' | 'kubernetes' = 'minikube'
deploy: boolean = false
diff --git a/karavan-core/test/application.spec.ts
b/karavan-core/test/application.spec.ts
index 6c9bc90..f701d6c 100644
--- a/karavan-core/test/application.spec.ts
+++ b/karavan-core/test/application.spec.ts
@@ -27,10 +27,10 @@ describe('Project configuration', () => {
expect(project.name).to.equal('demo');
expect(project.namespace).to.equal('development');
- project.tag = 'newtag/proj:latest';
+ project.image = 'newtag/proj:latest';
let newProperties = ProjectModelApi.updateProperties(props, project);
- const tag = newProperties.split(/\r?\n/).filter(l =>
l.startsWith("camel.jbang.build.image.tag"))[0].split("=")[1];
- expect(tag).to.equal(project.tag);
+ const tag = newProperties.split(/\r?\n/).filter(l =>
l.startsWith("camel.jbang.build.image.image"))[0].split("=")[1];
+ expect(tag).to.equal(project.image);
project.routesIncludePattern = "file:x";
diff --git a/karavan-demo/postman-openshift/application.properties
b/karavan-demo/postman-openshift/application.properties
index 6fbd28b..bd9fc4d 100644
--- a/karavan-demo/postman-openshift/application.properties
+++ b/karavan-demo/postman-openshift/application.properties
@@ -3,34 +3,31 @@ camel.jbang.project.name=postman
camel.jbang.project.version=1.0.0
camel.jbang.project.namespace=postman
camel.jbang.project.cleanup=false
-camel.jbang.package=true
+camel.jbang.package=false
camel.jbang.package.uber-jar.jar=camel-runner.jar
camel.jbang.package.uber-jar.fresh=true
camel.main.routesIncludePattern=file:CustomProcessor.java,file:postman.yaml
camel.jbang.build.image=true
-camel.jbang.build.image.openshift=true
-camel.jbang.build.image.minikube=false
+camel.jbang.build.image.openshift=false
+camel.jbang.build.image.build-config=true
+camel.jbang.build.image.push=false
camel.jbang.build.image.jar=camel-runner.jar
-camel.jbang.build.image.tag=postman/postman:1.0.0
+camel.jbang.build.image.image=postman/postman:1.0.0
camel.jbang.build.image.source-image=java:openjdk-11-ubi8
camel.jbang.build.image.from=gcr.io/distroless/java:11
-camel.jbang.build.image.server=https://api.cluster-wjw7l.wjw7l.sandbox1208.opentlc.com:6443
camel.jbang.deploy=true
-camel.jbang.deploy.openshift=true
-camel.jbang.deploy.minikube=false
+camel.jbang.deploy.openshift=false
+camel.jbang.deploy.minikube=true
camel.jbang.deploy.image=postman/postman:1.0.0
camel.jbang.deploy.replicas=1
camel.jbang.deploy.node-port=30777
-camel.jbang.deploy.server=https://api.cluster-wjw7l.wjw7l.sandbox1208.opentlc.com:6443
-camel.jbang.undeploy.openshift=true
-camel.jbang.undeploy.minikube=false
-camel.jbang.undeploy.server=https://api.cluster-wjw7l.wjw7l.sandbox1208.opentlc.com:6443
+camel.jbang.undeploy.openshift=false
+camel.jbang.undeploy.minikube=true
camel.jbang.manifests=true
camel.jbang.manifests.path=true
-camel.jbang.manifests.openshift=true
-camel.jbang.manifests.minikube=false
+camel.jbang.manifests.openshift=false
+camel.jbang.manifests.minikube=true
camel.jbang.manifests.image=postman/postman:1.0.0
camel.jbang.manifests.replicas=1
camel.jbang.manifests.node-port=30777
-camel.jbang.manifests.server=https://api.cluster-wjw7l.wjw7l.sandbox1208.opentlc.com:6443
camel.jbang.manifests.jar=camel-runner.jar
\ No newline at end of file
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 79d749b..c89c9b4 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -25,7 +25,7 @@ import {KameletsPage} from "./kamelets/KameletsPage";
import {ComponentsPage} from "./components/ComponentsPage";
import {EipPage} from "./eip/EipPage";
import {BuilderPage} from "./builder/BuilderPage";
-import {ProjectModel} from "karavan-core/lib/model/ProjectModel";
+import {ProjectModel, StepStatus} from "karavan-core/lib/model/ProjectModel";
interface Props {
page: "designer" | "kamelets" | "components" | "eip" | "builder";
@@ -119,7 +119,8 @@ class App extends React.Component<Props, State> {
public render() {
const project = ProjectModel.createNew();
project.status.active = true;
- project.status.uberJar = "progress";
+ project.status.uberJar = new StepStatus({status:"progress"});
+ project.status.build = new StepStatus({status:"progress"});
return (
<Page className="karavan">
{this.props.page === "designer" && <KaravanDesigner
key={this.state.key} filename={this.state.name} yaml={this.state.yaml}
diff --git a/karavan-designer/src/builder/BuilderPage.tsx
b/karavan-designer/src/builder/BuilderPage.tsx
index 1a9f85e..d5ed670 100644
--- a/karavan-designer/src/builder/BuilderPage.tsx
+++ b/karavan-designer/src/builder/BuilderPage.tsx
@@ -48,7 +48,7 @@ import DeployIcon from
'@patternfly/react-icons/dist/esm/icons/cloud-upload-alt-
import CleanupIcon from '@patternfly/react-icons/dist/esm/icons/remove2-icon';
import ProjectIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
import {FileSelector} from "./FileSelector";
-import {ProjectModel, ProjectStatus} from
"karavan-core/lib/model/ProjectModel";
+import {ProjectModel, ProjectStatus, StepStatus} from
"karavan-core/lib/model/ProjectModel";
interface Props {
dark: boolean
@@ -63,13 +63,15 @@ interface State {
version: string,
filename: string,
namespace: string,
- tag?: string,
+ image?: string,
sourceImage: string,
from: string,
replicas: number,
nodePort: number,
server?: string,
token?: string,
+ username?: string,
+ password?: string,
target: 'openshift' | 'minikube' | 'kubernetes',
deploy: boolean,
build: boolean,
@@ -81,16 +83,26 @@ interface State {
manifests: boolean,
buildConfig: boolean,
path: string,
+ key?: string;
}
export class BuilderPage extends React.Component<Props, State> {
public state: State = this.props.project;
+ interval:any;
componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
this.props.onChange?.call(this, this.state);
}
+ componentDidMount() {
+ this.interval = setInterval(() => this.setState(state => ({ key:
Math.random().toString()})), 1000);
+ }
+
+ componentWillUnmount() {
+ clearInterval(this.interval);
+ }
+
getHelp(text: string) {
return <Popover
aria-label={text}
@@ -114,6 +126,16 @@ export class BuilderPage extends React.Component<Props,
State> {
</FormGroup>
}
+ getBuildConfigField() {
+ const {buildConfig} = this.state;
+ return <FormGroup label="Use BuildConfig" fieldId="buildConfig"
isRequired={true}>
+ <InputGroup style={{display:"flex", flexDirection:"row",
justifyContent:"end", alignItems:"center"}}>
+ <Switch isChecked={buildConfig} onChange={checked =>
this.setState({buildConfig: checked})} id="buildConfig"/>
+ {this.getHelp("Use BuildConfig for build in OpenShift ")}
+ </InputGroup>
+ </FormGroup>
+ }
+
getCardHeader(title: string, icon: any, optional: boolean = true, checked:
boolean = false, onCheck?: (check: boolean) => void) {
return <CardHeader>
<CardHeaderMain>
@@ -158,12 +180,12 @@ export class BuilderPage extends React.Component<Props,
State> {
}
getBuildForm() {
- const {target, namespace, build, tag, sourceImage, server, token,
from} = this.state;
+ const {target, namespace, build, image, sourceImage, server, token,
from, buildConfig, username, password} = this.state;
return <Card className="builder-card" isCompact style={{width:
"100%"}}>
{this.getCardHeader("Build", <ImageIcon/>, true, this.state.build,
check => this.setState({build: check}))}
<CardBody className={build ? "" : "card-disabled"}>
<Form isHorizontal>
- <FormGroup label="Target" fieldId="tag" isRequired
disabled={true}>
+ <FormGroup label="Target" fieldId="target" isRequired
disabled={true}>
<ToggleGroup aria-label="Select target">
<ToggleGroupItem isDisabled={!build}
text="Minikube" buttonId="minikube" isSelected={target === 'minikube'}
onChange={selected => selected ?
this.setState({target: 'minikube'}) : {}}/>
@@ -174,11 +196,14 @@ export class BuilderPage extends React.Component<Props,
State> {
</ToggleGroup>
</FormGroup>
{this.getField("namespace", "Namespace", "text",
namespace, "Namespace to build and/or deploy", val => this.setState({namespace:
val}), true, build)}
- {this.getField("tag", "Image tag", "text", tag, "Image
tag", val => this.setState({tag: val}), true, build)}
- {target !== 'openshift' && this.getField("from", "Base
Image", "text", from, "Base Image", val => this.setState({from: val}), true,
build)}
- {target === 'openshift' && this.getField("sourceImage",
"Source tag", "text", sourceImage, "Source image name (for OpenShift
BuildConfig)", val => this.setState({sourceImage: val}), true, build)}
- {target === 'openshift' && this.getField("server",
"Server", "text", server, "Master URL", val => this.setState({server: val}),
true, build)}
- {target === 'openshift' && this.getField("token", "Token",
"password", token, "Authentication Token (Token will not be saved)", val =>
this.setState({token: val}), true, build)}
+ {this.getField("image", "Image name", "text", image,
"Image name", val => this.setState({image: val}), true, build)}
+ {target === 'openshift' && this.getBuildConfigField()}
+ {!buildConfig && this.getField("from", "Base Image",
"text", from, "Base Image", val => this.setState({from: val}), true, build)}
+ {target === 'openshift' && buildConfig &&
this.getField("sourceImage", "Source Image", "text", sourceImage, "Source image
name (for OpenShift BuildConfig)", val => this.setState({sourceImage: val}),
true, build)}
+ {target !== 'minikube' && this.getField("server",
"Server", "text", server, "Master URL", val => this.setState({server: val}),
true, build)}
+ {target !== 'minikube' && this.getField("username",
"Username", "text", username, "Username", val => this.setState({username:
val}), false, build)}
+ {target !== 'minikube' && this.getField("password",
"Password", "password", password, "Password (will not be saved)", val =>
this.setState({password: val}), false, build)}
+ {target !== 'minikube' && this.getField("token", "Token",
"password", token, "Authentication Token (will not be saved)", val =>
this.setState({token: val}), false, build)}
</Form>
</CardBody>
</Card>
@@ -209,7 +234,7 @@ export class BuilderPage extends React.Component<Props,
State> {
</Card>
}
- getProgressIcon(status: 'pending' | 'progress' | 'done' | 'error') {
+ getProgressIcon(status?: 'pending' | 'progress' | 'done' | 'error') {
switch (status) {
case "pending":
return <PendingIcon/>;
@@ -224,16 +249,42 @@ export class BuilderPage extends React.Component<Props,
State> {
}
}
+ getDescription(stepStatus?: StepStatus){
+ const now = Date.now();
+ let time = 0 ;
+ if (stepStatus?.status === 'progress') {
+ time = stepStatus?.startTime ? (now - stepStatus.startTime) / 1000
: 0;
+ } else if (stepStatus?.status === 'done' && stepStatus?.endTime){
+ time = (stepStatus?.endTime - stepStatus.startTime) / 1000
+ }
+ return time === 0 ? "" : Math.round(time) + "s";
+ }
+
getProgress() {
const {status, uberJar, build, deploy} = this.state;
- const undeploying = status.active && status.undeploy === "progress";
+ const undeploying = status.active && status.undeploy?.status ===
"progress";
return (
<ProgressStepper isCenterAligned style={{visibility: "visible"}}>
- {!undeploying && uberJar && <ProgressStep variant="pending"
id="package" titleId="package" aria-label="package"
icon={this.getProgressIcon(status.uberJar)}>Package</ProgressStep>}
- {!undeploying && build && <ProgressStep variant="pending"
isCurrent id="build" titleId="build" aria-label="build"
icon={this.getProgressIcon(status.build)}>Build</ProgressStep>}
- {!undeploying && deploy && <ProgressStep variant="pending"
id="deploy" titleId="deploy" aria-label="deploy"
icon={this.getProgressIcon(status.deploy)}>Deploy</ProgressStep>}
+ {!undeploying && uberJar &&
+ <ProgressStep variant="pending" id="package"
titleId="package" aria-label="package"
+
description={this.getDescription(status.uberJar)}
+
icon={this.getProgressIcon(status.uberJar?.status)}>Package
+ </ProgressStep>}
+ {!undeploying && build &&
+ <ProgressStep variant="pending" isCurrent id="build"
titleId="build" aria-label="build"
+
description={this.getDescription(status.build)}
+
icon={this.getProgressIcon(status.build?.status)}>Build
+ </ProgressStep>}
+ {!undeploying && deploy &&
+ <ProgressStep variant="pending" id="deploy"
titleId="deploy" aria-label="deploy"
+
description={this.getDescription(status.deploy)}
+
icon={this.getProgressIcon(status.deploy?.status)}>Deploy
+ </ProgressStep>}
{undeploying &&
- <ProgressStep variant="pending" id="undeploy"
titleId="undeploy" aria-label="undeploy"
icon={this.getProgressIcon(status.undeploy)}>Undeploy</ProgressStep>}
+ <ProgressStep variant="pending" id="undeploy"
titleId="undeploy" aria-label="undeploy"
+
description={this.getDescription(status.undeploy)}
+
icon={this.getProgressIcon(status.undeploy?.status)}>Undeploy
+ </ProgressStep>}
</ProgressStepper>
)
}
@@ -271,7 +322,7 @@ export class BuilderPage extends React.Component<Props,
State> {
const active = this.state.status.active;
const label = active ? "Stop" : "Start";
const icon = active ? <InProgressIcon/> : <AutomationIcon/>;
- return <div className="footer">
+ return <div key={this.state.key} className="footer">
<div className="progress">
{active && this.getProgress()}
</div>
diff --git a/karavan-vscode/src/builderView.ts
b/karavan-vscode/src/builderView.ts
index 1199b6f..2cd3fe6 100644
--- a/karavan-vscode/src/builderView.ts
+++ b/karavan-vscode/src/builderView.ts
@@ -19,7 +19,7 @@ import * as fs from "fs";
import * as path from "path";
import * as utils from "./utils";
import * as commands from "./commands";
-import { ProjectModel } from "karavan-core/lib/model/ProjectModel";
+import { ProjectModel, StepStatus } from "karavan-core/lib/model/ProjectModel";
import { ProjectModelApi } from "karavan-core/lib/api/ProjectModelApi";
let builderPanel: vscode.WebviewPanel | undefined;
@@ -109,27 +109,27 @@ export class BuilderView {
start(project: ProjectModel) {
const [x, files] = this.readProjectInfo(this.rootPath || '');
project.status.active = true;
- project.status.uberJar = "pending";
- project.status.build = "pending";
- project.status.deploy = "pending";
- project.status.undeploy = "pending";
+ project.status.uberJar = new StepStatus()
+ project.status.build = new StepStatus()
+ project.status.deploy = new StepStatus()
+ project.status.undeploy = new StepStatus()
if (project.uberJar) {
- project.status.uberJar = "progress";
+ project.status.uberJar = StepStatus.progress();
builderPanel?.webview.postMessage({ command: 'project', files:
files, project: project });
this.package(project, files);
} else if (project.build) {
- project.status.uberJar = "done";
+ project.status.uberJar.status = "done";
this.buildImage(project, files);
}
}
package(project: ProjectModel, files: string) {
console.log("package", project);
- project.status.uberJar = "progress";
+ project.status.uberJar = StepStatus.progress();
builderPanel?.webview.postMessage({ command: 'project', files: files,
project: project });
commands.camelJbangPackage(this.rootPath || "", code => {
- project.status.uberJar = code === 0 ? "done" : "error";
+ project.status.uberJar = code === 0 ?
StepStatus.done(project.status.uberJar) :
StepStatus.error(project.status.uberJar);
builderPanel?.webview.postMessage({ command: 'project', files:
files, project: project });
if (code === 0 && project.build) {
this.buildImage(project, files);
@@ -141,11 +141,11 @@ export class BuilderView {
buildImage(project: ProjectModel, files: string) {
console.log("buildImage", project);
- project.status.build = "progress";
+ project.status.build = StepStatus.progress();
builderPanel?.webview.postMessage({ command: 'project', files: files,
project: project });
commands.camelJbangBuildImage(this.rootPath || "", project, code => {
- project.status.build = code === 0 ? "done" : "error";
+ project.status.build = code === 0 ?
StepStatus.done(project.status.build) : StepStatus.error(project.status.build);
builderPanel?.webview.postMessage({ command: 'project', files:
files, project: project });
if (code === 0 && project.deploy) {
this.deploy(project, files);
@@ -157,11 +157,11 @@ export class BuilderView {
deploy(project: ProjectModel, files: string) {
console.log("deploy", project);
- project.status.deploy = "progress";
+ project.status.deploy = StepStatus.progress();
builderPanel?.webview.postMessage({ command: 'project', files: files,
project: project });
commands.camelJbangDeploy(this.rootPath || "", project, code => {
- project.status.deploy = code === 0 ? "done" : "error";
+ project.status.deploy = code === 0 ?
StepStatus.done(project.status.deploy) :
StepStatus.error(project.status.deploy);
builderPanel?.webview.postMessage({ command: 'project', files:
files, project: project });
this.finish(project, files, code);
});
@@ -204,7 +204,7 @@ export class BuilderView {
const [x, files] = this.readProjectInfo(this.rootPath || '');
console.log("undelpoy", project);
project.status.active = true;
- project.status.undeploy = "progress";
+ project.status.undeploy = StepStatus.progress();
builderPanel?.webview.postMessage({ command: 'project', files: files,
project: project });
commands.camelJbangUndeploy(this.rootPath || '', project, (code) =>
this.finish(project, files, code));
}
diff --git a/karavan-vscode/src/commands.ts b/karavan-vscode/src/commands.ts
index 6be1b06..e801a9d 100644
--- a/karavan-vscode/src/commands.ts
+++ b/karavan-vscode/src/commands.ts
@@ -107,8 +107,9 @@ export function cacheClear(rootPath: string, callback:
(code: number) => any) {
function prepareCommand(command: string, project?: ProjectModel): string {
const version = vscode.workspace.getConfiguration().get("camel.version");
- const token = project && project.target === 'openshift' ? " --token " +
project.token : "";
- return "jbang -Dcamel.jbang.version=" + version + " camel@apache/camel " +
command + token;
+ const token = project && project.target ? " --token " + project.token : "";
+ const password = project && project.password ? " --password " +
project.password : "";
+ return "jbang -Dcamel.jbang.version=" + version + " camel@apache/camel " +
command + token + password;
}
function executeJbangCommand(rootPath: string, command: string, callback:
(code: number, stdout: any, stderr: any) => any) {
diff --git a/karavan-vscode/webview/builder/BuilderPage.tsx
b/karavan-vscode/webview/builder/BuilderPage.tsx
index 6b33006..d5ed670 100644
--- a/karavan-vscode/webview/builder/BuilderPage.tsx
+++ b/karavan-vscode/webview/builder/BuilderPage.tsx
@@ -48,7 +48,7 @@ import DeployIcon from
'@patternfly/react-icons/dist/esm/icons/cloud-upload-alt-
import CleanupIcon from '@patternfly/react-icons/dist/esm/icons/remove2-icon';
import ProjectIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
import {FileSelector} from "./FileSelector";
-import {ProjectModel, ProjectStatus} from
"karavan-core/lib/model/ProjectModel";
+import {ProjectModel, ProjectStatus, StepStatus} from
"karavan-core/lib/model/ProjectModel";
interface Props {
dark: boolean
@@ -63,13 +63,15 @@ interface State {
version: string,
filename: string,
namespace: string,
- tag?: string,
+ image?: string,
sourceImage: string,
from: string,
replicas: number,
nodePort: number,
server?: string,
token?: string,
+ username?: string,
+ password?: string,
target: 'openshift' | 'minikube' | 'kubernetes',
deploy: boolean,
build: boolean,
@@ -79,17 +81,28 @@ interface State {
status: ProjectStatus,
cleanup: boolean,
manifests: boolean,
+ buildConfig: boolean,
path: string,
+ key?: string;
}
export class BuilderPage extends React.Component<Props, State> {
public state: State = this.props.project;
+ interval:any;
componentDidUpdate = (prevProps: Readonly<Props>, prevState:
Readonly<State>, snapshot?: any) => {
this.props.onChange?.call(this, this.state);
}
+ componentDidMount() {
+ this.interval = setInterval(() => this.setState(state => ({ key:
Math.random().toString()})), 1000);
+ }
+
+ componentWillUnmount() {
+ clearInterval(this.interval);
+ }
+
getHelp(text: string) {
return <Popover
aria-label={text}
@@ -113,6 +126,16 @@ export class BuilderPage extends React.Component<Props,
State> {
</FormGroup>
}
+ getBuildConfigField() {
+ const {buildConfig} = this.state;
+ return <FormGroup label="Use BuildConfig" fieldId="buildConfig"
isRequired={true}>
+ <InputGroup style={{display:"flex", flexDirection:"row",
justifyContent:"end", alignItems:"center"}}>
+ <Switch isChecked={buildConfig} onChange={checked =>
this.setState({buildConfig: checked})} id="buildConfig"/>
+ {this.getHelp("Use BuildConfig for build in OpenShift ")}
+ </InputGroup>
+ </FormGroup>
+ }
+
getCardHeader(title: string, icon: any, optional: boolean = true, checked:
boolean = false, onCheck?: (check: boolean) => void) {
return <CardHeader>
<CardHeaderMain>
@@ -157,12 +180,12 @@ export class BuilderPage extends React.Component<Props,
State> {
}
getBuildForm() {
- const {target, namespace, build, tag, sourceImage, server, token,
from} = this.state;
+ const {target, namespace, build, image, sourceImage, server, token,
from, buildConfig, username, password} = this.state;
return <Card className="builder-card" isCompact style={{width:
"100%"}}>
{this.getCardHeader("Build", <ImageIcon/>, true, this.state.build,
check => this.setState({build: check}))}
<CardBody className={build ? "" : "card-disabled"}>
<Form isHorizontal>
- <FormGroup label="Target" fieldId="tag" isRequired
disabled={true}>
+ <FormGroup label="Target" fieldId="target" isRequired
disabled={true}>
<ToggleGroup aria-label="Select target">
<ToggleGroupItem isDisabled={!build}
text="Minikube" buttonId="minikube" isSelected={target === 'minikube'}
onChange={selected => selected ?
this.setState({target: 'minikube'}) : {}}/>
@@ -173,11 +196,14 @@ export class BuilderPage extends React.Component<Props,
State> {
</ToggleGroup>
</FormGroup>
{this.getField("namespace", "Namespace", "text",
namespace, "Namespace to build and/or deploy", val => this.setState({namespace:
val}), true, build)}
- {this.getField("tag", "Image tag", "text", tag, "Image
tag", val => this.setState({tag: val}), true, build)}
- {target !== 'openshift' && this.getField("from", "Base
Image", "text", from, "Base Image", val => this.setState({from: val}), true,
build)}
- {target === 'openshift' && this.getField("sourceImage",
"Source tag", "text", sourceImage, "Source image name (for OpenShift
BuildConfig)", val => this.setState({sourceImage: val}), true, build)}
- {target === 'openshift' && this.getField("server",
"Server", "text", server, "Master URL", val => this.setState({server: val}),
true, build)}
- {target === 'openshift' && this.getField("token", "Token",
"password", token, "Authentication Token (Token will not be saved)", val =>
this.setState({token: val}), true, build)}
+ {this.getField("image", "Image name", "text", image,
"Image name", val => this.setState({image: val}), true, build)}
+ {target === 'openshift' && this.getBuildConfigField()}
+ {!buildConfig && this.getField("from", "Base Image",
"text", from, "Base Image", val => this.setState({from: val}), true, build)}
+ {target === 'openshift' && buildConfig &&
this.getField("sourceImage", "Source Image", "text", sourceImage, "Source image
name (for OpenShift BuildConfig)", val => this.setState({sourceImage: val}),
true, build)}
+ {target !== 'minikube' && this.getField("server",
"Server", "text", server, "Master URL", val => this.setState({server: val}),
true, build)}
+ {target !== 'minikube' && this.getField("username",
"Username", "text", username, "Username", val => this.setState({username:
val}), false, build)}
+ {target !== 'minikube' && this.getField("password",
"Password", "password", password, "Password (will not be saved)", val =>
this.setState({password: val}), false, build)}
+ {target !== 'minikube' && this.getField("token", "Token",
"password", token, "Authentication Token (will not be saved)", val =>
this.setState({token: val}), false, build)}
</Form>
</CardBody>
</Card>
@@ -208,7 +234,7 @@ export class BuilderPage extends React.Component<Props,
State> {
</Card>
}
- getProgressIcon(status: 'pending' | 'progress' | 'done' | 'error') {
+ getProgressIcon(status?: 'pending' | 'progress' | 'done' | 'error') {
switch (status) {
case "pending":
return <PendingIcon/>;
@@ -223,16 +249,42 @@ export class BuilderPage extends React.Component<Props,
State> {
}
}
+ getDescription(stepStatus?: StepStatus){
+ const now = Date.now();
+ let time = 0 ;
+ if (stepStatus?.status === 'progress') {
+ time = stepStatus?.startTime ? (now - stepStatus.startTime) / 1000
: 0;
+ } else if (stepStatus?.status === 'done' && stepStatus?.endTime){
+ time = (stepStatus?.endTime - stepStatus.startTime) / 1000
+ }
+ return time === 0 ? "" : Math.round(time) + "s";
+ }
+
getProgress() {
const {status, uberJar, build, deploy} = this.state;
- const undeploying = status.active && status.undeploy === "progress";
+ const undeploying = status.active && status.undeploy?.status ===
"progress";
return (
<ProgressStepper isCenterAligned style={{visibility: "visible"}}>
- {!undeploying && uberJar && <ProgressStep variant="pending"
id="package" titleId="package" aria-label="package"
icon={this.getProgressIcon(status.uberJar)}>Package</ProgressStep>}
- {!undeploying && build && <ProgressStep variant="pending"
isCurrent id="build" titleId="build" aria-label="build"
icon={this.getProgressIcon(status.build)}>Build</ProgressStep>}
- {!undeploying && deploy && <ProgressStep variant="pending"
id="deploy" titleId="deploy" aria-label="deploy"
icon={this.getProgressIcon(status.deploy)}>Deploy</ProgressStep>}
+ {!undeploying && uberJar &&
+ <ProgressStep variant="pending" id="package"
titleId="package" aria-label="package"
+
description={this.getDescription(status.uberJar)}
+
icon={this.getProgressIcon(status.uberJar?.status)}>Package
+ </ProgressStep>}
+ {!undeploying && build &&
+ <ProgressStep variant="pending" isCurrent id="build"
titleId="build" aria-label="build"
+
description={this.getDescription(status.build)}
+
icon={this.getProgressIcon(status.build?.status)}>Build
+ </ProgressStep>}
+ {!undeploying && deploy &&
+ <ProgressStep variant="pending" id="deploy"
titleId="deploy" aria-label="deploy"
+
description={this.getDescription(status.deploy)}
+
icon={this.getProgressIcon(status.deploy?.status)}>Deploy
+ </ProgressStep>}
{undeploying &&
- <ProgressStep variant="pending" id="undeploy"
titleId="undeploy" aria-label="undeploy"
icon={this.getProgressIcon(status.undeploy)}>Undeploy</ProgressStep>}
+ <ProgressStep variant="pending" id="undeploy"
titleId="undeploy" aria-label="undeploy"
+
description={this.getDescription(status.undeploy)}
+
icon={this.getProgressIcon(status.undeploy?.status)}>Undeploy
+ </ProgressStep>}
</ProgressStepper>
)
}
@@ -270,7 +322,7 @@ export class BuilderPage extends React.Component<Props,
State> {
const active = this.state.status.active;
const label = active ? "Stop" : "Start";
const icon = active ? <InProgressIcon/> : <AutomationIcon/>;
- return <div className="footer">
+ return <div key={this.state.key} className="footer">
<div className="progress">
{active && this.getProgress()}
</div>
diff --git a/karavan-vscode/webview/components/ComponentCard.tsx
b/karavan-vscode/webview/components/ComponentCard.tsx
index e1adb01..925c720 100644
--- a/karavan-vscode/webview/components/ComponentCard.tsx
+++ b/karavan-vscode/webview/components/ComponentCard.tsx
@@ -34,7 +34,7 @@ export class ComponentCard extends React.Component<Props,
State> {
onClick={event => this.click(event)}
>
<CardHeader>
- <img draggable="false" src={camelIcon}
className="kamelet-icon" alt=""></img>
+ {CamelUi.getIconFromSource(camelIcon)}
</CardHeader>
<CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
<CardBody>{component.component.description}</CardBody>
diff --git a/karavan-vscode/webview/components/ComponentModal.tsx
b/karavan-vscode/webview/components/ComponentModal.tsx
index 25e72cc..04ad022 100644
--- a/karavan-vscode/webview/components/ComponentModal.tsx
+++ b/karavan-vscode/webview/components/ComponentModal.tsx
@@ -11,7 +11,7 @@ import {
import '../designer/karavan.css';
import {TableComposable, Tbody, Td, Th, Thead, Tr} from
"@patternfly/react-table";
import {Component} from "karavan-core/lib/model/ComponentModels";
-import {camelIcon} from "../designer/utils/CamelUi";
+import {camelIcon, CamelUi} from "../designer/utils/CamelUi";
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
import {ComponentProperty} from "karavan-core/src/core/model/ComponentModels";
@@ -69,7 +69,7 @@ export class ComponentModal extends React.Component<Props,
State> {
<Flex direction={{default: 'column'}}
key={component?.component.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false" src={camelIcon}
className="kamelet-icon" alt=""></img>
+ {CamelUi.getIconFromSource(camelIcon)}
<CardActions>
<Badge className="badge"
isRead> {component?.component.label}</Badge>
diff --git a/karavan-vscode/webview/eip/EipCard.tsx
b/karavan-vscode/webview/eip/EipCard.tsx
index 34d745e..310d429 100644
--- a/karavan-vscode/webview/eip/EipCard.tsx
+++ b/karavan-vscode/webview/eip/EipCard.tsx
@@ -33,7 +33,7 @@ export class EipCard extends React.Component<Props, State> {
onClick={event => this.click(event)}
>
<CardHeader>
- <img draggable="false"
src={CamelUi.getIconForName(component.className)} className="kamelet-icon"
alt=""></img>
+ {CamelUi.getIconForDslName(component.className)}
</CardHeader>
<CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
<CardBody>{component.description}</CardBody>
diff --git a/karavan-vscode/webview/eip/EipModal.tsx
b/karavan-vscode/webview/eip/EipModal.tsx
index ea5e325..f6ee6d9 100644
--- a/karavan-vscode/webview/eip/EipModal.tsx
+++ b/karavan-vscode/webview/eip/EipModal.tsx
@@ -62,7 +62,7 @@ export class EipModal extends React.Component<Props, State> {
<Flex direction={{default: 'column'}} key={component?.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false"
src={CamelUi.getIconForName(component?.name || '')} className="kamelet-icon"
alt=""></img>
+ {component &&
CamelUi.getIconForDslName(component?.className)}
<CardActions>
<Badge className="badge"
isRead> {component?.labels}</Badge>
diff --git a/karavan-vscode/webview/kamelets/KameletCard.tsx
b/karavan-vscode/webview/kamelets/KameletCard.tsx
index 8e05901..3708af8 100644
--- a/karavan-vscode/webview/kamelets/KameletCard.tsx
+++ b/karavan-vscode/webview/kamelets/KameletCard.tsx
@@ -33,7 +33,7 @@ export class KameletCard extends React.Component<Props,
State> {
onClick={event => this.click(event)}
>
<CardHeader>
- <img draggable="false" src={kamelet.icon()}
className="kamelet-icon" alt=""></img>
+ {CamelUi.getIconFromSource(kamelet.icon())}
</CardHeader>
<CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
<CardBody>{kamelet.spec.definition.description}</CardBody>
diff --git a/karavan-vscode/webview/kamelets/KameletModal.tsx
b/karavan-vscode/webview/kamelets/KameletModal.tsx
index 738c68a..fb9532d 100644
--- a/karavan-vscode/webview/kamelets/KameletModal.tsx
+++ b/karavan-vscode/webview/kamelets/KameletModal.tsx
@@ -11,6 +11,7 @@ import {
import '../designer/karavan.css';
import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from
"@patternfly/react-table";
+import {CamelUi} from "../designer/utils/CamelUi";
interface Props {
kamelet?: KameletModel,
@@ -66,7 +67,7 @@ export class KameletModal extends Component<Props, State> {
<Flex direction={{default: 'column'}}
key={this.state.kamelet?.metadata.name}
className="kamelet-modal-card">
<CardHeader>
- <img draggable="false"
src={this.state.kamelet?.icon()} className="kamelet-icon" alt=""></img>
+ {this.state.kamelet &&
CamelUi.getIconFromSource(this.state.kamelet?.icon())}
<CardActions>
<Badge className="badge"
isRead>
{this.state.kamelet?.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>