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 2022/11/19 02:03:32 UTC
[camel-karavan] branch main updated (b6b4fc3 -> 83ab986)
This is an automated email from the ASF dual-hosted git repository.
marat pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
from b6b4fc3 OpenAPi rest generator UI
new b35c2f2 Export folder from properties or input field
new 0643df5 Create camel.yaml plain route integration
new 19f4185 Cleanup designer
new f1382d7 Align Look and feel
new 49a4129 Align Look and feel
new ee8a689 Project Id could not be templates or kamelets
new dc1356f Kamalets in projects
new d7e0cfd Show custom kamelets
new e139453 Filter custom Kamelets
new e60eba6 Templates and Kamelets project list
new 2bc3324 Templates and Kamelets project list
new 83ab986 Templates and Kamelets project panel
The 12 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../apache/camel/karavan/api/KameletResources.java | 29 +-
.../apache/camel/karavan/api/ProjectResource.java | 10 +-
.../apache/camel/karavan/api/TemplateResource.java | 61 ----
.../org/apache/camel/karavan/model/Kamelet.java | 6 -
.../camel/karavan/service/ImportService.java | 21 +-
.../camel/karavan/service/InfinispanService.java | 19 --
karavan-app/src/main/webui/package-lock.json | 81 ++++--
karavan-app/src/main/webui/src/Main.tsx | 12 +-
karavan-app/src/main/webui/src/api/KaravanApi.tsx | 22 +-
.../main/webui/src/components/ComponentCard.tsx | 2 +-
.../src/main/webui/src/dashboard/DashboardPage.tsx | 35 ++-
.../src/main/webui/src/designer/DesignerPage.tsx | 10 +-
.../src/main/webui/src/designer/karavan.css | 25 +-
.../src/main/webui/src/designer/utils/CamelUi.tsx | 13 -
karavan-app/src/main/webui/src/eip/EipCard.tsx | 2 +-
karavan-app/src/main/webui/src/index.css | 18 +-
.../src/main/webui/src/kamelets/KameletCard.tsx | 11 +-
.../src/main/webui/src/kamelets/KameletsPage.tsx | 43 +--
.../main/webui/src/projects/CreateFileModal.tsx | 2 +-
.../main/webui/src/projects/ProjectFilesTable.tsx | 116 ++++++++
.../src/main/webui/src/projects/ProjectInfo.tsx | 2 +-
.../src/main/webui/src/projects/ProjectModels.ts | 19 +-
.../src/main/webui/src/projects/ProjectPage.tsx | 316 +++++++++------------
.../main/webui/src/projects/ProjectPageToolbar.tsx | 4 +-
.../src/main/webui/src/projects/ProjectsPage.tsx | 179 +++++-------
.../main/webui/src/projects/ProjectsTableRow.tsx | 131 +++++++++
karavan-core/src/core/api/KameletApi.ts | 10 +
karavan-designer/src/App.tsx | 2 +-
karavan-designer/src/components/ComponentCard.tsx | 2 +-
karavan-designer/src/designer/karavan.css | 25 +-
karavan-designer/src/designer/utils/CamelUi.tsx | 13 -
karavan-designer/src/eip/EipCard.tsx | 2 +-
karavan-designer/src/kamelets/KameletCard.tsx | 11 +-
karavan-designer/src/kamelets/KameletsPage.tsx | 43 +--
karavan-space/src/space/SpacePage.tsx | 3 +-
karavan-vscode/src/designerView.ts | 2 +-
karavan-vscode/src/extension.ts | 80 ++++--
karavan-vscode/src/jbang.ts | 10 +-
38 files changed, 804 insertions(+), 588 deletions(-)
delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/api/TemplateResource.java
delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/model/Kamelet.java
create mode 100644 karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx
create mode 100644 karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
[camel-karavan] 05/12: Align Look and feel
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 49a41295bd64b493c17f96cdcdbbba45d2cbcf50
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 17:33:07 2022 -0500
Align Look and feel
---
karavan-app/src/main/webui/src/index.css | 4 +-
.../src/main/webui/src/projects/ProjectInfo.tsx | 2 +-
.../src/main/webui/src/projects/ProjectModels.ts | 4 +-
.../src/main/webui/src/projects/ProjectPage.tsx | 162 ++++++++++++---------
4 files changed, 95 insertions(+), 77 deletions(-)
diff --git a/karavan-app/src/main/webui/src/index.css b/karavan-app/src/main/webui/src/index.css
index efa6238..c9a66fb 100644
--- a/karavan-app/src/main/webui/src/index.css
+++ b/karavan-app/src/main/webui/src/index.css
@@ -133,8 +133,8 @@
font-size: 15px;
}
-.karavan .project-page .table {
- margin-top: 16px;
+.karavan .project-page .project-info {
+ margin-bottom: 16px;
}
.karavan .project-page .project-button {
diff --git a/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx
index f8525e5..79df4ca 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectInfo.tsx
@@ -415,7 +415,7 @@ export class ProjectInfo extends React.Component<Props, State> {
render() {
return (
- <Card>
+ <Card className="project-info">
<CardBody>
<Flex direction={{default: "row"}}
style={{height: "200px"}}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectModels.ts b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
index 6ceb51b..9e8e522 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectModels.ts
+++ b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
@@ -100,7 +100,7 @@ export const ProjectFileTypes: ProjectFileType[] = [
new ProjectFileType("INTEGRATION", "Integration", "camel.yaml"),
new ProjectFileType("CODE", "Code", "java"),
new ProjectFileType("PROPERTIES", "Properties", "properties"),
- new ProjectFileType("OPENAPI_JSON", "OpenAPI YAML", "json"),
- new ProjectFileType("OPENAPI_YAML", "OpenAPI JSON", "yaml"),
+ new ProjectFileType("OPENAPI_JSON", "OpenAPI JSON", "json"),
+ new ProjectFileType("OPENAPI_YAML", "OpenAPI YAML", "yaml"),
new ProjectFileType("LOG", "Log", "log"),
];
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index e1edd56..387d875 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -94,9 +94,7 @@ export class ProjectPage extends React.Component<Props, State> {
onRefresh = () => {
if (this.props.project) {
KaravanApi.getProject(this.props.project.projectId, (project: Project) => {
- this.setState({
- project: project
- })
+ this.setState({project: project})
});
KaravanApi.getFiles(this.props.project.projectId, (files: []) => {
this.setState({files: files})
@@ -154,7 +152,7 @@ export class ProjectPage extends React.Component<Props, State> {
addProperty() {
const file = this.state.file;
- if (file){
+ if (file) {
const project = file ? ProjectModelApi.propertiesToProject(file?.code) : ProjectModel.createNew();
const props = project.properties;
props.push(ProjectProperty.createNew("", ""))
@@ -165,19 +163,19 @@ export class ProjectPage extends React.Component<Props, State> {
tools = () => {
return <ProjectPageToolbar
- project={this.props.project}
- file={this.state.file}
- mode={this.state.mode}
- isTemplates={this.props.isTemplates}
- config={this.props.config}
- addProperty={() => this.addProperty()}
- download={() => this.download()}
- downloadImage={() => this.downloadImage()}
- editAdvancedProperties={this.state.editAdvancedProperties}
- setEditAdvancedProperties={checked => this.setState({editAdvancedProperties: checked})}
- setMode={mode => this.setState({mode: mode})}
- setCreateModalOpen={() => this.setState({isCreateModalOpen: true})}
- setUploadModalOpen={() => this.setState({isUploadModalOpen: true})}
+ project={this.props.project}
+ file={this.state.file}
+ mode={this.state.mode}
+ isTemplates={this.props.isTemplates}
+ config={this.props.config}
+ addProperty={() => this.addProperty()}
+ download={() => this.download()}
+ downloadImage={() => this.downloadImage()}
+ editAdvancedProperties={this.state.editAdvancedProperties}
+ setEditAdvancedProperties={checked => this.setState({editAdvancedProperties: checked})}
+ setMode={mode => this.setState({mode: mode})}
+ setCreateModalOpen={() => this.setState({isCreateModalOpen: true})}
+ setUploadModalOpen={() => this.setState({isUploadModalOpen: true})}
/>
}
@@ -334,12 +332,12 @@ export class ProjectPage extends React.Component<Props, State> {
const filename = name + ".log";
const code = '';
this.setState({file: new ProjectFile(filename, this.props.project.projectId, code)});
- if (type === 'pipeline'){
+ if (type === 'pipeline') {
KaravanApi.getPipelineLog(environment, name, (res: any) => {
if (Array.isArray(res) && Array.from(res).length > 0)
this.setState({file: new ProjectFile(filename, this.props.project.projectId, res.at(0).log)});
});
- } else if (type === 'container'){
+ } else if (type === 'container') {
KaravanApi.getContainerLog(environment, name, (res: any) => {
this.setState({file: new ProjectFile(filename, this.props.project.projectId, res)});
});
@@ -349,15 +347,17 @@ export class ProjectPage extends React.Component<Props, State> {
deleteEntity = (type: 'pod' | 'deployment', name: string, environment: string) => {
switch (type) {
- case "deployment": KaravanApi.deleteDeployment(environment, name, (res: any) => {
- if (Array.isArray(res) && Array.from(res).length > 0)
- this.onRefresh();
- });
+ case "deployment":
+ KaravanApi.deleteDeployment(environment, name, (res: any) => {
+ if (Array.isArray(res) && Array.from(res).length > 0)
+ this.onRefresh();
+ });
break;
- case "pod": KaravanApi.deletePod(environment, name, (res: any) => {
- if (Array.isArray(res) && Array.from(res).length > 0)
- this.onRefresh();
- });
+ case "pod":
+ KaravanApi.deletePod(environment, name, (res: any) => {
+ if (Array.isArray(res) && Array.from(res).length > 0)
+ this.onRefresh();
+ });
break;
}
}
@@ -367,22 +367,22 @@ export class ProjectPage extends React.Component<Props, State> {
return (
<div style={{overflow: "auto"}}>
{file !== undefined && file.code.length !== 0 &&
- <CodeBlock style={{width:"90%"}}>
+ <CodeBlock style={{width: "90%"}}>
<CodeBlockCode id="code-content">{file.code}</CodeBlockCode>
</CodeBlock>}
{(file === undefined || file.code.length === 0) &&
<div>
- <Skeleton width="25%" screenreaderText="Loading contents" />
- <br />
- <Skeleton width="33%" />
- <br />
- <Skeleton width="50%" />
- <br />
- <Skeleton width="66%" />
- <br />
- <Skeleton width="75%" />
- <br />
- <Skeleton />
+ <Skeleton width="25%" screenreaderText="Loading contents"/>
+ <br/>
+ <Skeleton width="33%"/>
+ <br/>
+ <Skeleton width="50%"/>
+ <br/>
+ <Skeleton width="66%"/>
+ <br/>
+ <Skeleton width="75%"/>
+ <br/>
+ <Skeleton/>
</div>}
</div>
)
@@ -393,16 +393,44 @@ export class ProjectPage extends React.Component<Props, State> {
return (
file !== undefined &&
<PropertiesEditor key={this.state.key}
- editAdvanced={this.state.editAdvancedProperties}
- file={file}
- onSave={(name, code) => this.save(name, code)}
+ editAdvanced={this.state.editAdvancedProperties}
+ file={file}
+ onSave={(name, code) => this.save(name, code)}
/>
)
}
- render() {
- const {isTemplates} = this.props;
- const {file, mode, tab} = this.state;
+ getTemplatePanel() {
+ return (
+ <PageSection isFilled className="kamelets-page project-page-section" padding={{default: 'padding'}}>
+ {this.getProjectFiles()}
+ </PageSection>
+ )
+ }
+
+ getProjectPanel() {
+ const {tab} = this.state;
+ return (
+ <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
+ <FlexItem className="project-tabs">
+ <Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>
+ <Tab eventKey="development" title="Development"/>
+ <Tab eventKey="operations" title="Operations"/>
+ </Tabs>
+ </FlexItem>
+ <FlexItem>
+ <PageSection padding={{default: "padding"}}>
+ {tab === 'development' && <ProjectInfo project={this.props.project} config={this.props.config} deleteEntity={this.deleteEntity} showLog={this.showLogs}/>}
+ {tab === 'development' && this.getProjectFiles()}
+ {tab === 'operations' && <ProjectOperations environments={this.state.environments} project={this.props.project} config={this.props.config}/>}
+ </PageSection>
+ </FlexItem>
+ </Flex>
+ )
+ }
+
+ getFilePanel() {
+ const {file, mode} = this.state;
const isYaml = file !== undefined && file.name.endsWith("yaml");
const isIntegration = isYaml && file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code);
const isProperties = file !== undefined && file.name.endsWith("properties");
@@ -411,37 +439,27 @@ export class ProjectPage extends React.Component<Props, State> {
const showDesigner = isYaml && isIntegration && mode === 'design';
const showEditor = isCode || (isYaml && !isIntegration) || (isYaml && mode === 'code');
return (
- <PageSection className="kamelet-section project-page" padding={{default: 'noPadding'}}>
- <PageSection className="tools-section" padding={{default: 'noPadding'}}>
- <MainToolbar title={this.title()} tools={this.tools()}/>
- </PageSection>
- {file === undefined &&
- <PageSection isFilled className="kamelets-page project-page-section"
- padding={{default: file !== undefined ? 'noPadding' : 'noPadding'}}>
- <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
- {!isTemplates &&
- <FlexItem className="project-tabs">
- <Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>
- <Tab eventKey="development" title="Development"/>
- <Tab eventKey="operations" title="Operations"/>
- </Tabs>
- </FlexItem>
- }
- {!isTemplates &&
- <FlexItem>
- <PageSection padding={{default: "padding"}}>
- {tab === 'development' && <ProjectInfo project={this.props.project} config={this.props.config} deleteEntity={this.deleteEntity} showLog={this.showLogs}/>}
- {tab === 'development' && this.getProjectFiles()}
- {tab === 'operations' && <ProjectOperations environments={this.state.environments} project={this.props.project} config={this.props.config}/>}
- </PageSection>
- </FlexItem>
- }
- </Flex>
- </PageSection>}
+ <>
{showDesigner && this.getDesigner()}
{showEditor && this.getEditor()}
{isLog && this.getLogView()}
{isProperties && this.getPropertiesEditor()}
+ </>
+ )
+ }
+
+ render() {
+ const {isTemplates} = this.props;
+ const {file} = this.state;
+ return (
+ <PageSection className="kamelet-section project-page" padding={{default: 'noPadding'}}>
+ <PageSection className="tools-section" padding={{default: 'noPadding'}}>
+ <MainToolbar title={this.title()} tools={this.tools()}/>
+ </PageSection>
+ {file === undefined && isTemplates && this.getTemplatePanel()}
+ {file === undefined && !isTemplates && this.getProjectPanel()}
+ {file !== undefined && this.getFilePanel()}
+
<CreateFileModal project={this.props.project} isOpen={this.state.isCreateModalOpen}
onClose={this.closeModal}/>
<Modal
[camel-karavan] 02/12: Create camel.yaml plain route integration
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 0643df51b60a3c35ff88c786f11aa96ea75177f5
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 16:26:49 2022 -0500
Create camel.yaml plain route integration
---
karavan-app/src/main/webui/package-lock.json | 81 ++++++++++++++--------
.../main/webui/src/components/ComponentCard.tsx | 2 +-
.../src/main/webui/src/designer/DesignerPage.tsx | 10 +--
.../src/main/webui/src/designer/utils/CamelUi.tsx | 13 ----
karavan-app/src/main/webui/src/eip/EipCard.tsx | 2 +-
.../src/main/webui/src/kamelets/KameletCard.tsx | 2 +-
.../main/webui/src/projects/CreateFileModal.tsx | 2 +-
.../src/main/webui/src/projects/ProjectModels.ts | 6 +-
.../src/main/webui/src/projects/ProjectPage.tsx | 36 +++-------
.../main/webui/src/projects/ProjectPageToolbar.tsx | 4 +-
10 files changed, 77 insertions(+), 81 deletions(-)
diff --git a/karavan-app/src/main/webui/package-lock.json b/karavan-app/src/main/webui/package-lock.json
index 6077662..76ae782 100644
--- a/karavan-app/src/main/webui/package-lock.json
+++ b/karavan-app/src/main/webui/package-lock.json
@@ -39,6 +39,28 @@
"monaco-editor": "0.29.1"
}
},
+ "../../../../karavan-core": {
+ "version": "3.18.6",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/js-yaml": "^4.0.5",
+ "@types/uuid": "^8.3.4",
+ "typescript": "^4.5.5",
+ "uuid": "8.3.2"
+ },
+ "devDependencies": {
+ "@types/chai": "^4.3.0",
+ "@types/dagre": "^0.7.47",
+ "@types/localforage": "0.0.34",
+ "@types/mocha": "^9.1.0",
+ "@types/node": "^17.0.23",
+ "chai": "^4.3.4",
+ "cross-env": "^7.0.3",
+ "fs": "^0.0.1-security",
+ "mocha": "^9.2.0",
+ "ts-node": "^10.4.0"
+ }
+ },
"../karavan-core": {
"extraneous": true
},
@@ -4534,9 +4556,9 @@
}
},
"node_modules/babel-loader/node_modules/loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
+ "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -10889,15 +10911,8 @@
}
},
"node_modules/karavan-core": {
- "version": "3.18.6",
- "resolved": "file:../../../../karavan-core",
- "license": "Apache-2.0",
- "dependencies": {
- "@types/js-yaml": "^4.0.5",
- "@types/uuid": "^8.3.4",
- "typescript": "^4.5.5",
- "uuid": "8.3.2"
- }
+ "resolved": "../../../../karavan-core",
+ "link": true
},
"node_modules/keycloak-js": {
"version": "19.0.1",
@@ -10995,9 +11010,9 @@
}
},
"node_modules/loader-utils": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
- "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -13450,9 +13465,9 @@
}
},
"node_modules/react-dev-utils/node_modules/loader-utils": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz",
- "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==",
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz",
+ "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==",
"engines": {
"node": ">= 12.13.0"
}
@@ -19866,9 +19881,9 @@
}
},
"loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
+ "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -24472,10 +24487,20 @@
}
},
"karavan-core": {
- "version": "3.18.6",
+ "version": "file:../../../../karavan-core",
"requires": {
+ "@types/chai": "^4.3.0",
+ "@types/dagre": "^0.7.47",
"@types/js-yaml": "^4.0.5",
+ "@types/localforage": "0.0.34",
+ "@types/mocha": "^9.1.0",
+ "@types/node": "^17.0.23",
"@types/uuid": "^8.3.4",
+ "chai": "^4.3.4",
+ "cross-env": "^7.0.3",
+ "fs": "^0.0.1-security",
+ "mocha": "^9.2.0",
+ "ts-node": "^10.4.0",
"typescript": "^4.5.5",
"uuid": "8.3.2"
}
@@ -24555,9 +24580,9 @@
"integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw=="
},
"loader-utils": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
- "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -26207,9 +26232,9 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"loader-utils": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz",
- "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ=="
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz",
+ "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw=="
},
"supports-color": {
"version": "7.2.0",
diff --git a/karavan-app/src/main/webui/src/components/ComponentCard.tsx b/karavan-app/src/main/webui/src/components/ComponentCard.tsx
index 1fe5269..ba18bd4 100644
--- a/karavan-app/src/main/webui/src/components/ComponentCard.tsx
+++ b/karavan-app/src/main/webui/src/components/ComponentCard.tsx
@@ -51,7 +51,7 @@ export class ComponentCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconFromSource(camelIcon)}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
+ <CardTitle>{component.component.title}</CardTitle>
<CardBody>{component.component.description}</CardBody>
<CardFooter>
<Badge isRead className="labels">{component.component.label}</Badge>
diff --git a/karavan-app/src/main/webui/src/designer/DesignerPage.tsx b/karavan-app/src/main/webui/src/designer/DesignerPage.tsx
index fb05426..baee350 100644
--- a/karavan-app/src/main/webui/src/designer/DesignerPage.tsx
+++ b/karavan-app/src/main/webui/src/designer/DesignerPage.tsx
@@ -30,7 +30,7 @@ interface Props {
name: string,
yaml: string,
dark: boolean,
- onSave?: (filename: string, yaml: string, propertyOnly: boolean) => void
+ onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
}
interface State {
@@ -83,16 +83,16 @@ export class DesignerPage extends React.Component<Props, State> {
<Toolbar id="toolbar-group-types">
<ToolbarContent>
<ToolbarItem>
- <Tooltip content="Download source" position={"bottom-end"}>
+ <Tooltip content="Download YAML" position={"bottom"}>
<Button variant="primary" icon={<DownloadIcon/>} onClick={e => this.download()}>
- Download yaml
+ YAML
</Button>
</Tooltip>
</ToolbarItem>
<ToolbarItem>
- <Tooltip content="Download image" position={"bottom-end"}>
+ <Tooltip content="Download image" position={"bottom"}>
<Button variant="secondary" icon={<DownloadImageIcon/>} onClick={e => this.downloadImage()}>
- Download image
+ Image
</Button>
</Tooltip>
</ToolbarItem>
diff --git a/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx b/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx
index 3083c36..5c98f13 100644
--- a/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx
+++ b/karavan-app/src/main/webui/src/designer/utils/CamelUi.tsx
@@ -196,19 +196,6 @@ export class CamelUi {
return name.split("-").map(v => CamelUtil.capitalizeName(v)).join('');
}
- static titleFromName = (name?: string) => {
- name = name ? (name.substring(0, name.lastIndexOf('.')) || name) : undefined;
- return name
- ? name
- .replace(".yaml", "")
- .split("-")
- .map((value) => CamelUtil.capitalizeName(value))
- .reduce(
- (previousValue, currentValue) => previousValue + " " + currentValue
- )
- : name;
- }
-
static isActionKamelet = (element: CamelElement): boolean => {
const kamelet = CamelUtil.getKamelet(element);
if (kamelet) return kamelet.type() === 'action'
diff --git a/karavan-app/src/main/webui/src/eip/EipCard.tsx b/karavan-app/src/main/webui/src/eip/EipCard.tsx
index 0fab47e..bfb2f8d 100644
--- a/karavan-app/src/main/webui/src/eip/EipCard.tsx
+++ b/karavan-app/src/main/webui/src/eip/EipCard.tsx
@@ -51,7 +51,7 @@ export class EipCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconForDslName(component.className)}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
+ <CardTitle>{component.title}</CardTitle>
<CardBody>{component.description}</CardBody>
<CardFooter>
<Badge isRead className="labels">{component.labels}</Badge>
diff --git a/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx b/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx
index 2bae9fc..20d4388 100644
--- a/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx
@@ -51,7 +51,7 @@ export class KameletCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
+ <CardTitle>{kamelet.spec.definition.title}</CardTitle>
<CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
{/*<div style={{justifyContent: "space-between"}}>*/}
diff --git a/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx b/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx
index 3072cf4..e2143f3 100644
--- a/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx
+++ b/karavan-app/src/main/webui/src/projects/CreateFileModal.tsx
@@ -41,7 +41,7 @@ export class CreateFileModal extends React.Component<Props, State> {
const extension = ProjectFileTypes.filter(value => value.name === fileType)[0].extension;
const filename = (extension !== 'java') ? CamelUi.nameFromTitle(name) : CamelUi.javaNameFromTitle(name);
const code = fileType === 'INTEGRATION'
- ? CamelDefinitionYaml.integrationToYaml(Integration.createNew(name))
+ ? CamelDefinitionYaml.integrationToYaml(Integration.createNew(name, 'plain'))
: '';
if (filename && extension){
const file = new ProjectFile(filename + '.' + extension, this.props.project.projectId, code);
diff --git a/karavan-app/src/main/webui/src/projects/ProjectModels.ts b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
index 1b8515d..6ceb51b 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectModels.ts
+++ b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
@@ -97,10 +97,10 @@ export class ProjectFileType {
}
export const ProjectFileTypes: ProjectFileType[] = [
- new ProjectFileType("INTEGRATION", "Integration", "yaml"),
+ new ProjectFileType("INTEGRATION", "Integration", "camel.yaml"),
new ProjectFileType("CODE", "Code", "java"),
new ProjectFileType("PROPERTIES", "Properties", "properties"),
- new ProjectFileType("OPENAPI", "OpenAPI", "json"),
- new ProjectFileType("OPENAPI", "OpenAPI", "yaml"),
+ new ProjectFileType("OPENAPI_JSON", "OpenAPI YAML", "json"),
+ new ProjectFileType("OPENAPI_YAML", "OpenAPI JSON", "yaml"),
new ProjectFileType("LOG", "Log", "log"),
];
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index ed3dbb4..e09b981 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -7,8 +7,6 @@ import {
PageSection,
Text,
TextContent,
- Toolbar,
- ToolbarContent,
Bullseye,
EmptyState,
EmptyStateVariant,
@@ -18,10 +16,8 @@ import {
Modal,
Flex,
FlexItem,
- ToggleGroup,
- ToggleGroupItem,
CodeBlockCode,
- CodeBlock, Skeleton, Checkbox, Tabs, Tab, Tooltip, ToolbarItem
+ CodeBlock, Skeleton, Tabs, Tab
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {MainToolbar} from "../MainToolbar";
@@ -186,21 +182,11 @@ export class ProjectPage extends React.Component<Props, State> {
}
getType = (file: ProjectFile) => {
+ if (file.name.endsWith(".camel.yaml")) return ProjectFileTypes.filter(p => p.name === "INTEGRATION").map(p => p.title)[0];
+ if (file.name.endsWith(".json")) return ProjectFileTypes.filter(p => p.name === "OPENAPI_JSON").map(p => p.title)[0];
+ if (file.name.endsWith(".yaml")) return ProjectFileTypes.filter(p => p.name === "OPENAPI_YAML").map(p => p.title)[0];
const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
- if (extension === 'yaml') {
- const isIntegration = CamelDefinitionYaml.yamlIsIntegration(file.code);
- return isIntegration
- ? ProjectFileTypes.filter(p => p.name === "INTEGRATION").map(p => p.title)[0]
- : ProjectFileTypes.filter(p => p.name === "OPENAPI").map(p => p.title)[0];
- } else {
- const type = ProjectFileTypes.filter(p => p.extension === extension).map(p => p.title)[0];
- if (type) {
- return type
- return type
- } else {
- return "Unknown"
- }
- }
+ return ProjectFileTypes.filter(p => p.extension === extension).map(p => p.title)[0];
}
title = () => {
@@ -219,7 +205,7 @@ export class ProjectPage extends React.Component<Props, State> {
<BreadcrumbItem to="#" isActive>{this.getType(file)}</BreadcrumbItem>
</Breadcrumb>
<TextContent className="title">
- <Text component="h1">{isLog ? filename : CamelUi.titleFromName(file.name)}</Text>
+ <Text component="h1">{isLog ? filename : file.name}</Text>
</TextContent>
</div>
}
@@ -263,9 +249,8 @@ export class ProjectPage extends React.Component<Props, State> {
<TableComposable aria-label="Files" variant={"compact"} className={"table"}>
<Thead>
<Tr>
- <Th key='type'>Type</Th>
- <Th key='name'>Name</Th>
- <Th key='filename'>Filename</Th>
+ <Th key='type' width={10}>Type</Th>
+ <Th key='filename' width={50}>Filename</Th>
<Th key='action'></Th>
</Tr>
</Thead>
@@ -273,16 +258,15 @@ export class ProjectPage extends React.Component<Props, State> {
{files.map(file => {
const type = this.getType(file)
return <Tr key={file.name}>
- <Td modifier={"fitContent"}>
+ <Td>
<Badge>{type}</Badge>
</Td>
<Td>
<Button style={{padding: '6px'}} variant={"link"}
onClick={e => this.select(file)}>
- {CamelUi.titleFromName(file.name)}
+ {file.name}
</Button>
</Td>
- <Td>{file.name}</Td>
<Td modifier={"fitContent"}>
<Button style={{padding: '0'}} variant={"plain"}
isDisabled={file.name === 'application.properties'}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx b/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx
index 23b346f..93e2ec2 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPageToolbar.tsx
@@ -121,9 +121,9 @@ export class ProjectPageToolbar extends React.Component<Props> {
render() {
const {isTemplates} = this.props;
- return <Toolbar id="toolbar-group-types">
+ return <div>
{isTemplates && this.getTemplatesToolbar()}
{!isTemplates && this.getProjectToolbar()}
- </Toolbar>
+ </div>
}
}
[camel-karavan] 01/12: Export folder from properties or input field
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit b35c2f2d8af3cf2a0abb8fa66584e71ac94b1d7f
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 14:47:19 2022 -0500
Export folder from properties or input field
---
karavan-vscode/src/designerView.ts | 2 +-
karavan-vscode/src/extension.ts | 80 ++++++++++++++++++++++++++------------
karavan-vscode/src/jbang.ts | 10 +++--
3 files changed, 63 insertions(+), 29 deletions(-)
diff --git a/karavan-vscode/src/designerView.ts b/karavan-vscode/src/designerView.ts
index c16b373..1be8c9d 100644
--- a/karavan-vscode/src/designerView.ts
+++ b/karavan-vscode/src/designerView.ts
@@ -91,7 +91,7 @@ export class DesignerView {
const i = Integration.createNew(name);
i.type = type;
const yaml = CamelDefinitionYaml.integrationToYaml(i);
- const filename = name.toLocaleLowerCase().endsWith('.yaml') ? name : name + '.yaml';
+ const filename = name.toLocaleLowerCase().endsWith('.camel.yaml') ? name : name.split('.')[0] + '.camel.yaml';
const relativePath = (this.rootPath ? rootPath?.replace(this.rootPath, "") : rootPath) + path.sep + filename;
const fullPath = (rootPath ? rootPath : this.rootPath) + path.sep + filename;
utils.save(relativePath, yaml);
diff --git a/karavan-vscode/src/extension.ts b/karavan-vscode/src/extension.ts
index c7b5bfb..b816b0b 100644
--- a/karavan-vscode/src/extension.ts
+++ b/karavan-vscode/src/extension.ts
@@ -54,18 +54,18 @@ export function activate(context: ExtensionContext) {
</body>
</html>`
- .replace(
- "styleUri",
- Uri.joinPath(context.extensionUri, "/dist/main.css")
- .with({ scheme: "vscode-resource" })
- .toString()
- )
- .replace(
- "scriptUri",
- Uri.joinPath(context.extensionUri, "/dist/webview.js")
- .with({ scheme: "vscode-resource" })
- .toString()
- );
+ .replace(
+ "styleUri",
+ Uri.joinPath(context.extensionUri, "/dist/main.css")
+ .with({ scheme: "vscode-resource" })
+ .toString()
+ )
+ .replace(
+ "scriptUri",
+ Uri.joinPath(context.extensionUri, "/dist/webview.js")
+ .with({ scheme: "vscode-resource" })
+ .toString()
+ );
const rootPath = (workspace.workspaceFolders && (workspace.workspaceFolders.length > 0))
? workspace.workspaceFolders[0].uri.fsPath : undefined;
@@ -103,36 +103,36 @@ export function activate(context: ExtensionContext) {
// Create application
const applicationCommand = commands.registerCommand("karavan.create-application", (...args: any[]) => {
- if (rootPath){
+ if (rootPath) {
const defaultRuntime: string = workspace.getConfiguration().get("camel.runtimes") || '';
const deployTarget: string = workspace.getConfiguration().get("camel.deployTarget") || 'openshift';
- const runtimeOptions: QuickPickItem [] = [
- {label: "quarkus", picked: "quarkus" === defaultRuntime},
- {label: "spring-boot", picked: "spring-boot" === defaultRuntime}
+ const runtimeOptions: QuickPickItem[] = [
+ { label: "quarkus", picked: "quarkus" === defaultRuntime },
+ { label: "spring-boot", picked: "spring-boot" === defaultRuntime }
];
- const deployOptions: QuickPickItem [] = [
- {label: "openshift", picked: "openshift" === deployTarget},
- {label: "kubernetes", picked: "kubernetes" === deployTarget},
- {label: "none", picked: "none" === deployTarget}
+ const deployOptions: QuickPickItem[] = [
+ { label: "openshift", picked: "openshift" === deployTarget },
+ { label: "kubernetes", picked: "kubernetes" === deployTarget },
+ { label: "none", picked: "none" === deployTarget }
];
utils.hasApplicationProperties(rootPath).then(hasAP => {
- if (hasAP){
+ if (hasAP) {
window.showInformationMessage("Folder already contains application.properties");
} else {
window.showQuickPick(runtimeOptions, { title: "Select Runtime", canPickMany: false }).then((runtime) => {
window.showQuickPick(deployOptions, { title: "Select Deploy Target", canPickMany: false }).then((target) => {
- if (runtime && target) inputExportGav(runtime.label, target.label)
+ if (runtime && target) inputExportGav(runtime.label, target.label)
})
})
}
})
- }
+ }
});
context.subscriptions.push(applicationCommand);
// Export project
const exportCommand = commands.registerCommand("karavan.jbang-export", (...args: any[]) => {
- jbang.camelJbangExport();
+ exportProject(rootPath);
});
context.subscriptions.push(exportCommand);
@@ -178,6 +178,38 @@ export function activate(context: ExtensionContext) {
});
}
+/**
+ * export into folder
+ */
+export async function exportProject(rootPath?: string) {
+ utils.getExportFolder()
+ .then(folder => {
+ if (folder){
+ jbang.camelJbangExport();
+ } else {
+ window.showInputBox({
+ title: "Export project",
+ ignoreFocusOut: true,
+ prompt: "Export folder name",
+ value: ".export",
+ validateInput: (text: string): string | undefined => {
+ if (!text || text.length === 0) {
+ return 'Name should not be empty';
+ } else {
+ return undefined;
+ }
+ }
+ }).then(folder => {
+ if (folder && rootPath) {
+ const fullPath = rootPath + path.sep + folder;
+ jbang.camelJbangExport(fullPath);
+ }
+ });
+ }
+ }).catch(error => {
+ console.log(error);
+ })
+}
/**
* export with gav
diff --git a/karavan-vscode/src/jbang.ts b/karavan-vscode/src/jbang.ts
index e2baa92..456d46b 100644
--- a/karavan-vscode/src/jbang.ts
+++ b/karavan-vscode/src/jbang.ts
@@ -94,8 +94,8 @@ export function camelJbangRun(filename?: string) {
terminal.sendText(command);
}
-export function camelJbangExport() {
- const command = createExportCommand();
+export function camelJbangExport(fullPath?: string) {
+ const command = createExportCommand(fullPath);
const terminalId = "export";
const existTerminal = TERMINALS.get(terminalId);
if (existTerminal) existTerminal.dispose();
@@ -105,9 +105,11 @@ export function camelJbangExport() {
terminal.sendText(command);
}
-export function createExportCommand() {
+export function createExportCommand(fullPath?: string) {
const kameletsPath: string | undefined = workspace.getConfiguration().get("Karavan.kameletsPath");
- const cmd = "export --fresh " + (kameletsPath && kameletsPath.trim().length > 0 ? " --local-kamelet-dir=" + kameletsPath : "");
+ const cmd = "export --fresh "
+ + (fullPath ? " --directory=" + fullPath : '')
+ + (kameletsPath && kameletsPath.trim().length > 0 ? " --local-kamelet-dir=" + kameletsPath : "");
return prepareCommand(cmd);
}
[camel-karavan] 06/12: Project Id could not be templates or kamelets
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit ee8a689eba2cd03fb54bdb7543eb05b721fd9052
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 17:38:53 2022 -0500
Project Id could not be templates or kamelets
---
.../src/main/webui/src/projects/ProjectsPage.tsx | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index 320be76..fbb23d9 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -165,8 +165,9 @@ export class ProjectsPage extends React.Component<Props, State> {
}
createModalForm() {
- const {isCopy, projectToCopy, projectId, name, isCreateModalOpen} = this.state;
+ const {isCopy, projectToCopy, projectId, name, isCreateModalOpen, description, runtime} = this.state;
const {runtimes} = this.props.config;
+ const isReady = projectId && name && description && !['templates', 'kamelets'].includes(projectId);
return (
<Modal
title={!isCopy ? "Create new project" : "Copy project from " + projectToCopy?.projectId}
@@ -175,7 +176,7 @@ export class ProjectsPage extends React.Component<Props, State> {
onClose={this.closeModal}
onKeyDown={this.onKeyDown}
actions={[
- <Button key="confirm" variant="primary" onClick={this.saveAndCloseCreateModal}>Save</Button>,
+ <Button key="confirm" variant="primary" isDisabled={!isReady} onClick={this.saveAndCloseCreateModal}>Save</Button>,
<Button key="cancel" variant="secondary" onClick={this.closeModal}>Cancel</Button>
]}
className="new-project"
@@ -183,31 +184,31 @@ export class ProjectsPage extends React.Component<Props, State> {
<Form isHorizontal={true} autoComplete="off">
<FormGroup label="Name" fieldId="name" isRequired>
<TextInput className="text-field" type="text" id="name" name="name"
- value={this.state.name}
+ value={name}
onChange={e => this.setState({name: e})}/>
</FormGroup>
<FormGroup label="Description" fieldId="description" isRequired>
<TextInput className="text-field" type="text" id="description" name="description"
- value={this.state.description}
+ value={description}
onChange={e => this.setState({description: e})}/>
</FormGroup>
<FormGroup label="Project ID" fieldId="projectId" isRequired helperText="Unique project name">
<TextInput className="text-field" type="text" id="projectId" name="projectId"
- value={this.state.projectId}
+ value={projectId}
onFocus={e => this.setState({projectId: projectId === '' ? CamelUi.nameFromTitle(name) : projectId})}
onChange={e => this.setState({projectId: CamelUi.nameFromTitle(e)})}/>
</FormGroup>
<FormGroup label="Runtime" fieldId="runtime" isRequired>
- {runtimes?.map((runtime: string) => (
- <Radio key={runtime} id={runtime} name={runtime} className="radio"
- isChecked={this.state.runtime === runtime}
+ {runtimes?.map((r: string) => (
+ <Radio key={r} id={r} name={r} className="radio"
+ isChecked={r === runtime}
onChange={checked => {
- if (checked) this.setState({runtime: runtime})
+ if (checked) this.setState({runtime: r})
}}
body={
<div className="runtime-radio">
{runtime === 'quarkus' ? QuarkusIcon() : SpringIcon()}
- <div className="runtime-label">{CamelUtil.capitalizeName(runtime)}</div>
+ <div className="runtime-label">{CamelUtil.capitalizeName(r)}</div>
</div>}
/>
))}
[camel-karavan] 08/12: Show custom kamelets
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit d7e0cfd22813b17d10ced8efa90a685143075b84
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 18:27:57 2022 -0500
Show custom kamelets
---
.../apache/camel/karavan/api/KameletResources.java | 19 ++++++++++++++++-
.../apache/camel/karavan/api/ProjectResource.java | 4 ++--
karavan-app/src/main/webui/src/Main.tsx | 3 +++
karavan-app/src/main/webui/src/api/KaravanApi.tsx | 11 ++++++++++
.../src/main/webui/src/designer/karavan.css | 24 +++++++++++++++-------
.../src/main/webui/src/kamelets/KameletCard.tsx | 9 +++++---
karavan-core/src/core/api/KameletApi.ts | 10 +++++++++
karavan-designer/src/designer/karavan.css | 19 ++++++++++-------
karavan-designer/src/kamelets/KameletCard.tsx | 9 +++++---
9 files changed, 85 insertions(+), 23 deletions(-)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java
index d06f15d..afb61d2 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java
@@ -20,13 +20,16 @@ import org.apache.camel.karavan.model.Project;
import org.apache.camel.karavan.model.ProjectFile;
import org.apache.camel.karavan.service.CodeService;
import org.apache.camel.karavan.service.InfinispanService;
+import org.yaml.snakeyaml.Yaml;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
@Path("/api/kamelet")
@@ -40,7 +43,7 @@ public class KameletResources {
@GET
@Produces(MediaType.TEXT_PLAIN)
- public String getCustomYamls() {
+ public String getKamelets() {
StringBuilder kamelets = new StringBuilder(codeService.getResourceFile("/kamelets/kamelets.yaml"));
List<ProjectFile> custom = infinispanService.getProjectFiles(Project.NAME_KAMELETS);
if (custom.size() > 0) {
@@ -51,4 +54,18 @@ public class KameletResources {
}
return kamelets.toString();
}
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/names")
+ public List<String> getCustomNames() {
+ Yaml yaml = new Yaml();
+ return infinispanService.getProjectFiles(Project.NAME_KAMELETS).stream()
+ .map(projectFile -> {
+ Map<String, LinkedHashMap> obj = yaml.load(projectFile.getCode());
+ LinkedHashMap<String, Object> metadata = obj.get("metadata");
+ return metadata.get("name").toString();
+ })
+ .collect(Collectors.toList());
+ }
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
index b2e12b6..c6620cf 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
@@ -48,8 +48,8 @@ public class ProjectResource {
@Produces(MediaType.APPLICATION_JSON)
public List<Project> getAll() throws Exception {
return infinispanService.getProjects().stream()
- .filter(project -> !project.getName().equalsIgnoreCase(Project.NAME_TEMPLATES))
- .filter(project -> !project.getName().equalsIgnoreCase(Project.NAME_KAMELETS))
+ .filter(project -> !project.getProjectId().equalsIgnoreCase(Project.NAME_TEMPLATES))
+ .filter(project -> !project.getProjectId().equalsIgnoreCase(Project.NAME_KAMELETS))
.sorted(Comparator.comparing(Project::getProjectId))
.collect(Collectors.toList());
}
diff --git a/karavan-app/src/main/webui/src/Main.tsx b/karavan-app/src/main/webui/src/Main.tsx
index b37908d..5975cd2 100644
--- a/karavan-app/src/main/webui/src/Main.tsx
+++ b/karavan-app/src/main/webui/src/Main.tsx
@@ -140,6 +140,9 @@ export class Main extends React.Component<Props, State> {
yamls.split("\n---\n").map(c => c.trim()).forEach(z => kamelets.push(z));
KameletApi.saveKamelets(kamelets, true);
})
+ KaravanApi.getCustomKameletNames(names => {
+ KameletApi.saveCustomKameletNames(names);
+ })
});
}
diff --git a/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index e6e2003..c446efb 100644
--- a/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -446,6 +446,17 @@ export class KaravanApi {
});
}
+ static async getCustomKameletNames(after: (names: []) => void) {
+ instance.get('/api/kamelet/names')
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ console.log(err);
+ });
+ }
+
static async getComponents(after: (json: string) => void) {
instance.get('/api/component')
.then(res => {
diff --git a/karavan-app/src/main/webui/src/designer/karavan.css b/karavan-app/src/main/webui/src/designer/karavan.css
index 77ff41e..17b9f6b 100644
--- a/karavan-app/src/main/webui/src/designer/karavan.css
+++ b/karavan-app/src/main/webui/src/designer/karavan.css
@@ -125,7 +125,16 @@
}
.kamelets-page .kamelet-card .pf-c-card__header {
- padding-right: 6px;
+ /*padding-right: 6px;*/
+}
+
+.kamelets-page .kamelet-card .pf-c-card__header .custom {
+ margin-left: auto;
+}
+
+.kamelets-page .kamelet-card .pf-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
}
.kamelets-page .kamelet-card .pf-c-card__body {
@@ -145,6 +154,13 @@
user-select: none;
}
+.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+
/*kamelet modal*/
.kamelet-modal-card .pf-c-card__header {
padding-right: 6px;
@@ -1133,12 +1149,6 @@
margin-right: auto;
}
-/*Catalogues*/
-.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
.karavan .tools-section .tools .header {
display: flex;
diff --git a/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx b/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx
index 20d4388..5d4faaf 100644
--- a/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webui/src/kamelets/KameletCard.tsx
@@ -21,6 +21,7 @@ import {
import '../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
import {CamelUi} from "../designer/utils/CamelUi";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
interface Props {
kamelet: KameletModel,
@@ -44,19 +45,21 @@ export class KameletCard extends React.Component<Props, State> {
render() {
const kamelet = this.state.kamelet;
+ const isCustom = KameletApi.getCustomKameletNames().includes(kamelet.metadata.name);
return (
<Card isHoverable isCompact key={kamelet.metadata.name} className="kamelet-card"
- onClick={event => this.click(event)}
+ onClick={event => this.click(event)}
>
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
+ {isCustom && <Badge className="custom">custom</Badge>}
</CardHeader>
<CardTitle>{kamelet.spec.definition.title}</CardTitle>
<CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
{/*<div style={{justifyContent: "space-between"}}>*/}
- <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
- <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
+ <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
{/*</div>*/}
</CardFooter>
</Card>
diff --git a/karavan-core/src/core/api/KameletApi.ts b/karavan-core/src/core/api/KameletApi.ts
index d29bf32..ea1bd47 100644
--- a/karavan-core/src/core/api/KameletApi.ts
+++ b/karavan-core/src/core/api/KameletApi.ts
@@ -20,9 +20,19 @@ import {Component} from "../model/ComponentModels";
import {Components} from "./ComponentApi";
export const Kamelets: KameletModel[] = [];
+export const CustomNames: string[] = [];
export const KameletApi = {
+ getCustomKameletNames: (): string [] => {
+ return CustomNames;
+ },
+
+ saveCustomKameletNames: (names: string[]) => {
+ CustomNames.length = 0;
+ CustomNames.push(...names);
+ },
+
getKameletProperties: (kameletName: string): Property[] => {
const kamelet: KameletModel | undefined = KameletApi.findKameletByName(kameletName);
const properties: Property[] = [];
diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css
index ae823fb..17b9f6b 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -125,7 +125,11 @@
}
.kamelets-page .kamelet-card .pf-c-card__header {
- padding-right: 6px;
+ /*padding-right: 6px;*/
+}
+
+.kamelets-page .kamelet-card .pf-c-card__header .custom {
+ margin-left: auto;
}
.kamelets-page .kamelet-card .pf-c-card__title {
@@ -150,6 +154,13 @@
user-select: none;
}
+.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+
/*kamelet modal*/
.kamelet-modal-card .pf-c-card__header {
padding-right: 6px;
@@ -1138,12 +1149,6 @@
margin-right: auto;
}
-/*Catalogues*/
-.karavan .kamelets-page .kamelet-card .pf-c-card__footer {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
.karavan .tools-section .tools .header {
display: flex;
diff --git a/karavan-designer/src/kamelets/KameletCard.tsx b/karavan-designer/src/kamelets/KameletCard.tsx
index 20d4388..5d4faaf 100644
--- a/karavan-designer/src/kamelets/KameletCard.tsx
+++ b/karavan-designer/src/kamelets/KameletCard.tsx
@@ -21,6 +21,7 @@ import {
import '../designer/karavan.css';
import {KameletModel} from "karavan-core/lib/model/KameletModels";
import {CamelUi} from "../designer/utils/CamelUi";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
interface Props {
kamelet: KameletModel,
@@ -44,19 +45,21 @@ export class KameletCard extends React.Component<Props, State> {
render() {
const kamelet = this.state.kamelet;
+ const isCustom = KameletApi.getCustomKameletNames().includes(kamelet.metadata.name);
return (
<Card isHoverable isCompact key={kamelet.metadata.name} className="kamelet-card"
- onClick={event => this.click(event)}
+ onClick={event => this.click(event)}
>
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
+ {isCustom && <Badge className="custom">custom</Badge>}
</CardHeader>
<CardTitle>{kamelet.spec.definition.title}</CardTitle>
<CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
{/*<div style={{justifyContent: "space-between"}}>*/}
- <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
- <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
+ <Badge isRead className="labels">{kamelet.metadata.labels["camel.apache.org/kamelet.type"].toLowerCase()}</Badge>
+ <Badge isRead className="version">{kamelet.metadata.annotations["camel.apache.org/catalog.version"].toLowerCase()}</Badge>
{/*</div>*/}
</CardFooter>
</Card>
[camel-karavan] 03/12: Cleanup designer
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 19f41856ad106fe861278b94eefdd75fc0051a96
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 16:27:18 2022 -0500
Cleanup designer
---
karavan-designer/src/App.tsx | 2 +-
karavan-designer/src/components/ComponentCard.tsx | 2 +-
karavan-designer/src/designer/utils/CamelUi.tsx | 13 -------------
karavan-designer/src/eip/EipCard.tsx | 2 +-
karavan-designer/src/kamelets/KameletCard.tsx | 2 +-
karavan-space/src/space/SpacePage.tsx | 3 +--
6 files changed, 5 insertions(+), 19 deletions(-)
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 9af8955..10f2615 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -118,7 +118,7 @@ class App extends React.Component<Props, State> {
save(filename: string, yaml: string, propertyOnly: boolean) {
this.setState({name: filename, yaml: yaml});
- // console.log(yaml);
+ console.log(yaml);
}
getSpinner() {
diff --git a/karavan-designer/src/components/ComponentCard.tsx b/karavan-designer/src/components/ComponentCard.tsx
index 1fe5269..ba18bd4 100644
--- a/karavan-designer/src/components/ComponentCard.tsx
+++ b/karavan-designer/src/components/ComponentCard.tsx
@@ -51,7 +51,7 @@ export class ComponentCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconFromSource(camelIcon)}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(component.component.name)}</CardTitle>
+ <CardTitle>{component.component.title}</CardTitle>
<CardBody>{component.component.description}</CardBody>
<CardFooter>
<Badge isRead className="labels">{component.component.label}</Badge>
diff --git a/karavan-designer/src/designer/utils/CamelUi.tsx b/karavan-designer/src/designer/utils/CamelUi.tsx
index 3083c36..5c98f13 100644
--- a/karavan-designer/src/designer/utils/CamelUi.tsx
+++ b/karavan-designer/src/designer/utils/CamelUi.tsx
@@ -196,19 +196,6 @@ export class CamelUi {
return name.split("-").map(v => CamelUtil.capitalizeName(v)).join('');
}
- static titleFromName = (name?: string) => {
- name = name ? (name.substring(0, name.lastIndexOf('.')) || name) : undefined;
- return name
- ? name
- .replace(".yaml", "")
- .split("-")
- .map((value) => CamelUtil.capitalizeName(value))
- .reduce(
- (previousValue, currentValue) => previousValue + " " + currentValue
- )
- : name;
- }
-
static isActionKamelet = (element: CamelElement): boolean => {
const kamelet = CamelUtil.getKamelet(element);
if (kamelet) return kamelet.type() === 'action'
diff --git a/karavan-designer/src/eip/EipCard.tsx b/karavan-designer/src/eip/EipCard.tsx
index 0fab47e..bfb2f8d 100644
--- a/karavan-designer/src/eip/EipCard.tsx
+++ b/karavan-designer/src/eip/EipCard.tsx
@@ -51,7 +51,7 @@ export class EipCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconForDslName(component.className)}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(component.title)}</CardTitle>
+ <CardTitle>{component.title}</CardTitle>
<CardBody>{component.description}</CardBody>
<CardFooter>
<Badge isRead className="labels">{component.labels}</Badge>
diff --git a/karavan-designer/src/kamelets/KameletCard.tsx b/karavan-designer/src/kamelets/KameletCard.tsx
index 2bae9fc..20d4388 100644
--- a/karavan-designer/src/kamelets/KameletCard.tsx
+++ b/karavan-designer/src/kamelets/KameletCard.tsx
@@ -51,7 +51,7 @@ export class KameletCard extends React.Component<Props, State> {
<CardHeader>
{CamelUi.getIconFromSource(kamelet.icon())}
</CardHeader>
- <CardTitle>{CamelUi.titleFromName(kamelet.metadata.name)}</CardTitle>
+ <CardTitle>{kamelet.spec.definition.title}</CardTitle>
<CardBody>{kamelet.spec.definition.description}</CardBody>
<CardFooter>
{/*<div style={{justifyContent: "space-between"}}>*/}
diff --git a/karavan-space/src/space/SpacePage.tsx b/karavan-space/src/space/SpacePage.tsx
index 1cb9d7a..9365489 100644
--- a/karavan-space/src/space/SpacePage.tsx
+++ b/karavan-space/src/space/SpacePage.tsx
@@ -56,7 +56,6 @@ export class SpacePage extends React.Component<Props, State> {
save(filename: string, yaml: string, propertyOnly: boolean) {
this.props.onSave?.call(this, filename, yaml, propertyOnly);
- this.setState({key: Math.random().toString()})
}
download = () => {
@@ -84,8 +83,8 @@ export class SpacePage extends React.Component<Props, State> {
}
addYaml = (yaml: string | undefined) => {
- this.setState({showUploadModal: false });
this.save(this.props.name, this.props.yaml + "\n" + yaml, false);
+ this.setState({showUploadModal: false, key: Math.random().toString()})
}
getDesigner = () => {
[camel-karavan] 12/12: Templates and Kamelets project panel
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 83ab986f070a7ec7a853e07e0fa282ab0d9c88e0
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 21:03:18 2022 -0500
Templates and Kamelets project panel
---
.../main/webui/src/projects/ProjectFilesTable.tsx | 116 +++++++++++++++
.../src/main/webui/src/projects/ProjectModels.ts | 13 +-
.../src/main/webui/src/projects/ProjectPage.tsx | 165 +++++++--------------
.../src/main/webui/src/projects/ProjectsPage.tsx | 1 +
.../main/webui/src/projects/ProjectsTableRow.tsx | 32 +---
5 files changed, 185 insertions(+), 142 deletions(-)
diff --git a/karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx b/karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx
new file mode 100644
index 0000000..f1269e4
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/ProjectFilesTable.tsx
@@ -0,0 +1,116 @@
+import React from 'react';
+import {
+ Badge,
+ Breadcrumb,
+ BreadcrumbItem,
+ Button,
+ PageSection,
+ Text,
+ TextContent,
+ Bullseye,
+ EmptyState,
+ EmptyStateVariant,
+ EmptyStateIcon,
+ Title,
+ ModalVariant,
+ Modal,
+ Flex,
+ FlexItem,
+ CodeBlockCode,
+ CodeBlock, Skeleton, Tabs, Tab
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {MainToolbar} from "../MainToolbar";
+import {KaravanApi} from "../api/KaravanApi";
+import {getProjectFileType, Project, ProjectFile, ProjectFileTypes} from "./ProjectModels";
+import {CamelUi} from "../designer/utils/CamelUi";
+import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
+import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import {KaravanDesigner} from "../designer/KaravanDesigner";
+import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon";
+import DownloadImageIcon from "@patternfly/react-icons/dist/esm/icons/image-icon";
+import FileSaver from "file-saver";
+import Editor from "@monaco-editor/react";
+import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {CreateFileModal} from "./CreateFileModal";
+import {PropertiesEditor} from "./PropertiesEditor";
+import {ProjectModel, ProjectProperty} from "karavan-core/lib/model/ProjectModel";
+import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
+import {KubernetesAPI} from "../designer/utils/KubernetesAPI";
+import {UploadModal} from "./UploadModal";
+import {ProjectInfo} from "./ProjectInfo";
+import {ProjectOperations} from "./ProjectOperations";
+import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
+import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
+import {ProjectPageToolbar} from "./ProjectPageToolbar";
+
+interface Props {
+ files: ProjectFile[],
+ onOpenDeleteConfirmation: (file: ProjectFile) => void,
+ onSelect: (file: ProjectFile) => void,
+}
+
+interface State {
+
+}
+
+export class ProjectFilesTable extends React.Component<Props, State> {
+
+ public state: State = {};
+
+ render() {
+ const {files, onOpenDeleteConfirmation, onSelect} = this.props;
+ return (
+ <TableComposable aria-label="Files" variant={"compact"} className={"table"}>
+ <Thead>
+ <Tr>
+ <Th key='type' width={10}>Type</Th>
+ <Th key='filename' width={50}>Filename</Th>
+ <Th key='action'></Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {files.map(file => {
+ const type = getProjectFileType(file)
+ return <Tr key={file.name}>
+ <Td>
+ <Badge>{type}</Badge>
+ </Td>
+ <Td>
+ <Button style={{padding: '6px'}} variant={"link"}
+ onClick={e => onSelect.call(this, file)}>
+ {file.name}
+ </Button>
+ </Td>
+ <Td modifier={"fitContent"}>
+ {file.projectId !== 'templates' &&
+ <Button style={{padding: '0'}} variant={"plain"}
+ isDisabled={file.name === 'application.properties'}
+ onClick={e => onOpenDeleteConfirmation.call(this, file)}>
+ <DeleteIcon/>
+ </Button>
+ }
+ </Td>
+ </Tr>
+ })}
+ {files.length === 0 &&
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={SearchIcon}/>
+ <Title headingLevel="h2" size="lg">
+ No results found
+ </Title>
+ </EmptyState>
+ </Bullseye>
+ </Td>
+ </Tr>
+ }
+ </Tbody>
+ </TableComposable>
+ )
+ }
+}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectModels.ts b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
index 9e8e522..5764869 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectModels.ts
+++ b/karavan-app/src/main/webui/src/projects/ProjectModels.ts
@@ -98,9 +98,20 @@ export class ProjectFileType {
export const ProjectFileTypes: ProjectFileType[] = [
new ProjectFileType("INTEGRATION", "Integration", "camel.yaml"),
+ new ProjectFileType("KAMELET", "Kamelet", "kamelet.yaml"),
new ProjectFileType("CODE", "Code", "java"),
new ProjectFileType("PROPERTIES", "Properties", "properties"),
new ProjectFileType("OPENAPI_JSON", "OpenAPI JSON", "json"),
new ProjectFileType("OPENAPI_YAML", "OpenAPI YAML", "yaml"),
new ProjectFileType("LOG", "Log", "log"),
-];
\ No newline at end of file
+];
+
+
+export function getProjectFileType (file: ProjectFile) {
+ if (file.name.endsWith(".camel.yaml")) return ProjectFileTypes.filter(p => p.name === "INTEGRATION").map(p => p.title)[0];
+ if (file.name.endsWith(".kamelet.yaml")) return ProjectFileTypes.filter(p => p.name === "KAMELET").map(p => p.title)[0];
+ if (file.name.endsWith(".json")) return ProjectFileTypes.filter(p => p.name === "OPENAPI_JSON").map(p => p.title)[0];
+ if (file.name.endsWith(".yaml")) return ProjectFileTypes.filter(p => p.name === "OPENAPI_YAML").map(p => p.title)[0];
+ const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
+ return ProjectFileTypes.filter(p => p.extension === extension).map(p => p.title)[0];
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index b748442..8b71766 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -7,11 +7,6 @@ import {
PageSection,
Text,
TextContent,
- Bullseye,
- EmptyState,
- EmptyStateVariant,
- EmptyStateIcon,
- Title,
ModalVariant,
Modal,
Flex,
@@ -22,18 +17,10 @@ import {
import '../designer/karavan.css';
import {MainToolbar} from "../MainToolbar";
import {KaravanApi} from "../api/KaravanApi";
-import {Project, ProjectFile, ProjectFileTypes} from "./ProjectModels";
-import {CamelUi} from "../designer/utils/CamelUi";
-import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
-import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import {getProjectFileType, Project, ProjectFile, ProjectFileTypes} from "./ProjectModels";
import {KaravanDesigner} from "../designer/KaravanDesigner";
-import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon";
-import DownloadImageIcon from "@patternfly/react-icons/dist/esm/icons/image-icon";
import FileSaver from "file-saver";
import Editor from "@monaco-editor/react";
-import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {CreateFileModal} from "./CreateFileModal";
import {PropertiesEditor} from "./PropertiesEditor";
import {ProjectModel, ProjectProperty} from "karavan-core/lib/model/ProjectModel";
@@ -43,12 +30,11 @@ import {UploadModal} from "./UploadModal";
import {ProjectInfo} from "./ProjectInfo";
import {ProjectOperations} from "./ProjectOperations";
import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
import {ProjectPageToolbar} from "./ProjectPageToolbar";
+import {ProjectFilesTable} from "./ProjectFilesTable";
interface Props {
project: Project,
- isTemplates?: boolean,
config: any,
}
@@ -100,7 +86,7 @@ export class ProjectPage extends React.Component<Props, State> {
this.setState({files: files})
});
KubernetesAPI.inKubernetes = true;
- if (!this.props.isTemplates){
+ if (!this.isBuildIn()){
KaravanApi.getConfigMaps(this.state.environment, (any: []) => {
KubernetesAPI.setConfigMaps(any);
});
@@ -114,6 +100,10 @@ export class ProjectPage extends React.Component<Props, State> {
}
}
+ isBuildIn():boolean {
+ return ['kamelets', 'templates'].includes(this.props.project.projectId);
+ }
+
post = (file: ProjectFile) => {
KaravanApi.postProjectFile(file, res => {
if (res.status === 200) {
@@ -168,7 +158,7 @@ export class ProjectPage extends React.Component<Props, State> {
project={this.props.project}
file={this.state.file}
mode={this.state.mode}
- isTemplates={this.props.isTemplates}
+ isTemplates={this.isBuildIn()}
config={this.props.config}
addProperty={() => this.addProperty()}
download={() => this.download()}
@@ -180,17 +170,10 @@ export class ProjectPage extends React.Component<Props, State> {
setUploadModalOpen={() => this.setState({isUploadModalOpen: true})}
/>
}
-
- getType = (file: ProjectFile) => {
- if (file.name.endsWith(".camel.yaml")) return ProjectFileTypes.filter(p => p.name === "INTEGRATION").map(p => p.title)[0];
- if (file.name.endsWith(".json")) return ProjectFileTypes.filter(p => p.name === "OPENAPI_JSON").map(p => p.title)[0];
- if (file.name.endsWith(".yaml")) return ProjectFileTypes.filter(p => p.name === "OPENAPI_YAML").map(p => p.title)[0];
- const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
- return ProjectFileTypes.filter(p => p.extension === extension).map(p => p.title)[0];
- }
+
title = () => {
- const {project, isTemplates} = this.props;
+ const {project} = this.props;
const file = this.state.file;
const isFile = file !== undefined;
const isLog = file !== undefined && file.name.endsWith("log");
@@ -202,7 +185,7 @@ export class ProjectPage extends React.Component<Props, State> {
<BreadcrumbItem to="#" onClick={event => this.setState({file: undefined})}>
{"Project: " + project?.projectId}
</BreadcrumbItem>
- <BreadcrumbItem to="#" isActive>{this.getType(file)}</BreadcrumbItem>
+ <Badge>{getProjectFileType(file)}</Badge>
</Breadcrumb>
<TextContent className="title">
<Text component="h1">{isLog ? filename : file.name}</Text>
@@ -210,7 +193,7 @@ export class ProjectPage extends React.Component<Props, State> {
</div>
}
{!isFile && <TextContent className="title">
- <Text component="h2">{isTemplates ? 'Templates' : 'Project: ' + project?.projectId}</Text>
+ <Text component="h2">{project?.name}</Text>
</TextContent>}
</div>)
};
@@ -243,58 +226,6 @@ export class ProjectPage extends React.Component<Props, State> {
}
}
- getProjectFiles = () => {
- const files = this.state.files;
- return (
- <TableComposable aria-label="Files" variant={"compact"} className={"table"}>
- <Thead>
- <Tr>
- <Th key='type' width={10}>Type</Th>
- <Th key='filename' width={50}>Filename</Th>
- <Th key='action'></Th>
- </Tr>
- </Thead>
- <Tbody>
- {files.map(file => {
- const type = this.getType(file)
- return <Tr key={file.name}>
- <Td>
- <Badge>{type}</Badge>
- </Td>
- <Td>
- <Button style={{padding: '6px'}} variant={"link"}
- onClick={e => this.select(file)}>
- {file.name}
- </Button>
- </Td>
- <Td modifier={"fitContent"}>
- <Button style={{padding: '0'}} variant={"plain"}
- isDisabled={file.name === 'application.properties'}
- onClick={e => this.openDeleteConfirmation(file)}>
- <DeleteIcon/>
- </Button>
- </Td>
- </Tr>
- })}
- {files.length === 0 &&
- <Tr>
- <Td colSpan={8}>
- <Bullseye>
- <EmptyState variant={EmptyStateVariant.small}>
- <EmptyStateIcon icon={SearchIcon}/>
- <Title headingLevel="h2" size="lg">
- No results found
- </Title>
- </EmptyState>
- </Bullseye>
- </Td>
- </Tr>
- }
- </Tbody>
- </TableComposable>
- )
- }
-
getDesigner = () => {
const file = this.state.file;
return (
@@ -402,43 +333,50 @@ export class ProjectPage extends React.Component<Props, State> {
)
}
- getTemplatePanel() {
- const {tab} = this.state;
+ getProjectPanel() {
+ const isBuildIn = this.isBuildIn();
return (
<Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
- {/*<FlexItem className="project-tabs">*/}
- {/* <Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>*/}
- {/* <Tab eventKey="templates" title="Templates"/>*/}
- {/* <Tab eventKey="kamelets" title="Kamelets"/>*/}
- {/* </Tabs>*/}
- {/*</FlexItem>*/}
- <FlexItem>
- <PageSection padding={{default: "padding"}}>
- {this.getProjectFiles()}
- </PageSection>
- </FlexItem>
+ {!isBuildIn && this.getProjectPanelTabs()}
+ {this.getProjectPanelFiles()}
</Flex>
)
}
- getProjectPanel() {
+ getProjectPanelTabs() {
const {tab} = this.state;
return (
- <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
- <FlexItem className="project-tabs">
- <Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>
- <Tab eventKey="development" title="Development"/>
- <Tab eventKey="operations" title="Operations"/>
- </Tabs>
- </FlexItem>
- <FlexItem>
+ <FlexItem className="project-tabs">
+ <Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>
+ <Tab eventKey="development" title="Development"/>
+ <Tab eventKey="operations" title="Operations"/>
+ </Tabs>
+ </FlexItem>
+ )
+ }
+
+ getProjectPanelFiles() {
+ const {tab, files} = this.state;
+ const isBuildIn = this.isBuildIn();
+ return (
+ <FlexItem>
+ {isBuildIn &&
+ <PageSection padding={{default: "padding"}}>
+ {tab === 'development' && <ProjectFilesTable files={files}
+ onOpenDeleteConfirmation={this.openDeleteConfirmation}
+ onSelect={this.select}/>}
+ </PageSection>
+ }
+ {!isBuildIn &&
<PageSection padding={{default: "padding"}}>
{tab === 'development' && <ProjectInfo project={this.props.project} config={this.props.config} deleteEntity={this.deleteEntity} showLog={this.showLogs}/>}
- {tab === 'development' && this.getProjectFiles()}
+ {tab === 'development' && <ProjectFilesTable files={files}
+ onOpenDeleteConfirmation={this.openDeleteConfirmation}
+ onSelect={this.select}/>}
{tab === 'operations' && <ProjectOperations environments={this.state.environments} project={this.props.project} config={this.props.config}/>}
</PageSection>
- </FlexItem>
- </Flex>
+ }
+ </FlexItem>
)
}
@@ -462,23 +400,22 @@ export class ProjectPage extends React.Component<Props, State> {
}
render() {
- const {isTemplates} = this.props;
- const {file} = this.state;
+ const {file, isDeleteModalOpen, fileToDelete, isUploadModalOpen, isCreateModalOpen} = this.state;
+ const {project} = this.props;
return (
<PageSection className="kamelet-section project-page" padding={{default: 'noPadding'}}>
<PageSection className="tools-section" padding={{default: 'noPadding'}}>
<MainToolbar title={this.title()} tools={this.tools()}/>
</PageSection>
- {file === undefined && isTemplates && this.getTemplatePanel()}
- {file === undefined && !isTemplates && this.getProjectPanel()}
+ {file === undefined && this.getProjectPanel()}
{file !== undefined && this.getFilePanel()}
- <CreateFileModal project={this.props.project} isOpen={this.state.isCreateModalOpen}
+ <CreateFileModal project={project} isOpen={isCreateModalOpen}
onClose={this.closeModal}/>
<Modal
title="Confirmation"
variant={ModalVariant.small}
- isOpen={this.state.isDeleteModalOpen}
+ isOpen={isDeleteModalOpen}
onClose={() => this.setState({isDeleteModalOpen: false})}
actions={[
<Button key="confirm" variant="primary" onClick={e => this.delete()}>Delete</Button>,
@@ -486,9 +423,9 @@ export class ProjectPage extends React.Component<Props, State> {
onClick={e => this.setState({isDeleteModalOpen: false})}>Cancel</Button>
]}
onEscapePress={e => this.setState({isDeleteModalOpen: false})}>
- <div>{"Are you sure you want to delete the file " + this.state.fileToDelete?.name + "?"}</div>
+ <div>{"Are you sure you want to delete the file " + fileToDelete?.name + "?"}</div>
</Modal>
- <UploadModal projectId={this.props.project.projectId} isOpen={this.state.isUploadModalOpen} onClose={this.closeModal}/>
+ <UploadModal projectId={project.projectId} isOpen={isUploadModalOpen} onClose={this.closeModal}/>
</PageSection>
)
}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index b3a274e..63f056a 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -278,6 +278,7 @@ export class ProjectsPage extends React.Component<Props, State> {
config={this.props.config}
onSelect={this.props.onSelect}
onProjectDelete={this.onProjectDelete}
+ onProjectCopy={project1 => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project1})}
project={project}
deploymentStatuses={this.state.deploymentStatuses}/>
))}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
index 86723b5..8b8107a 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
@@ -43,40 +43,18 @@ interface Props {
config: any,
onSelect: (project: Project) => void
onProjectDelete: (project: Project) => void
+ onProjectCopy: (project: Project) => void
project: Project
deploymentStatuses: DeploymentStatus[],
}
interface State {
- projects: Project[],
- deploymentStatuses: DeploymentStatus[],
- isCreateModalOpen: boolean,
- isDeleteModalOpen: boolean,
- isCopy: boolean,
- loading: boolean,
- projectToCopy?: Project,
- projectToDelete?: Project,
- filter: string,
- name: string,
- description: string,
- projectId: string,
- runtime: string,
+
}
export class ProjectsTableRow extends React.Component<Props, State> {
public state: State = {
- projects: [],
- deploymentStatuses: [],
- isCreateModalOpen: false,
- isDeleteModalOpen: false,
- isCopy: false,
- loading: true,
- filter: '',
- name: '',
- description: '',
- projectId: '',
- runtime: this.props.config.runtime
};
getEnvironments(): string [] {
@@ -84,7 +62,7 @@ export class ProjectsTableRow extends React.Component<Props, State> {
}
getDeploymentByEnvironments(name: string): [string, DeploymentStatus | undefined] [] {
- const deps = this.state.deploymentStatuses;
+ const deps = this.props.deploymentStatuses;
return this.getEnvironments().map(e => {
const env: string = e as string;
const dep = deps.find(d => d.name === name && d.env === env);
@@ -93,7 +71,7 @@ export class ProjectsTableRow extends React.Component<Props, State> {
}
render() {
- const {project, onProjectDelete, onSelect} = this.props;
+ const {project, onProjectDelete, onSelect, onProjectCopy} = this.props;
const isBuildIn = ['kamelets', 'templates'].includes(project.projectId);
const badge = isBuildIn ? project.projectId.toUpperCase().charAt(0) : project.runtime.substring(0, 1).toUpperCase();
return (
@@ -134,7 +112,7 @@ export class ProjectsTableRow extends React.Component<Props, State> {
<OverflowMenuItem>
<Tooltip content={"Copy project"} position={"bottom"}>
<Button variant={"plain"} icon={<CopyIcon/>}
- onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
+ onClick={e => onProjectCopy.call(this, project)}></Button>
</Tooltip>
</OverflowMenuItem>
<OverflowMenuItem>
[camel-karavan] 09/12: Filter custom Kamelets
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit e13945352b462547e04a25d71a4e355b3f250d8f
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 19:14:55 2022 -0500
Filter custom Kamelets
---
.../src/main/webui/src/kamelets/KameletsPage.tsx | 43 +++++++++++++---------
.../src/main/webui/src/projects/ProjectPage.tsx | 37 +++++++++++++------
karavan-designer/src/kamelets/KameletsPage.tsx | 43 +++++++++++++---------
3 files changed, 77 insertions(+), 46 deletions(-)
diff --git a/karavan-app/src/main/webui/src/kamelets/KameletsPage.tsx b/karavan-app/src/main/webui/src/kamelets/KameletsPage.tsx
index 0635917..1c500e4 100644
--- a/karavan-app/src/main/webui/src/kamelets/KameletsPage.tsx
+++ b/karavan-app/src/main/webui/src/kamelets/KameletsPage.tsx
@@ -21,7 +21,7 @@ import {
Gallery,
ToolbarItem,
TextInput,
- PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem, Badge, Button
+ PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem, Badge, Button, Switch
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {KameletCard} from "./KameletCard";
@@ -41,7 +41,8 @@ interface State {
repository: string,
path: string,
kamelets: KameletModel[],
- filter: string
+ filter: string,
+ customOnly: boolean
}
export class KameletsPage extends React.Component<Props, State> {
@@ -51,7 +52,8 @@ export class KameletsPage extends React.Component<Props, State> {
repository: '',
path: '',
kamelets: [],
- filter: ''
+ filter: '',
+ customOnly: false
};
componentDidMount() {
@@ -63,26 +65,26 @@ export class KameletsPage extends React.Component<Props, State> {
}
search(filter: string) {
- this.setState({
- filter: filter,
- isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
- })
+ this.setState({ filter: filter, isModalOpen: false})
}
render() {
+ const {dark, onRefresh} = this.props;
+ const {kamelets, kamelet, isModalOpen, customOnly, filter} = this.state;
+ let kameletList = kamelets.filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
+ if (customOnly) kameletList = kameletList.filter(k => KameletApi.getCustomKameletNames().includes(k.metadata.name));
return (
- <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}
+ <PageSection variant={dark ? PageSectionVariants.darker : PageSectionVariants.light}
padding={{default: 'noPadding'}} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
+ <KameletModal key={kamelet?.metadata.name + isModalOpen.toString()}
+ isOpen={isModalOpen} kamelet={kamelet}/>
<PageSection className="tools-section"
- variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
+ variant={dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent className="header">
<Text component="h2">Kamelet Catalog</Text>
- <Badge isRead className="labels">{this.state.kamelets.length}</Badge>
+ <Badge isRead className="labels">{kamelets.length}</Badge>
</TextContent>
</FlexItem>
<FlexItem>
@@ -91,14 +93,21 @@ export class KameletsPage extends React.Component<Props, State> {
<ToolbarItem>
<Button icon={<RefreshIcon/>} variant="link"
onClick={e => {
- this.props.onRefresh?.call(this).then(value => {
+ onRefresh?.call(this).then(value => {
this.setState({kamelets: KameletApi.getKamelets()});
})
}}/>
</ToolbarItem>
+ <ToolbarItem>
+ <Switch
+ label="Custom only"
+ isChecked={customOnly}
+ onChange={checked => this.setState({customOnly: checked})}
+ />
+ </ToolbarItem>
<ToolbarItem>
<TextInput className="text-field" type="search" id="search" name="search"
- value={this.state.filter}
+ value={filter}
onChange={value => this.search(value)}
autoComplete="off"
placeholder="Search by name"/>
@@ -109,9 +118,9 @@ export class KameletsPage extends React.Component<Props, State> {
</Flex>
</PageSection>
<PageSection isFilled className="kamelets-page"
- variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
+ variant={dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
+ {kameletList.map(k => (
<KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
))}
</Gallery>
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index 387d875..b748442 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -100,15 +100,17 @@ export class ProjectPage extends React.Component<Props, State> {
this.setState({files: files})
});
KubernetesAPI.inKubernetes = true;
- KaravanApi.getConfigMaps(this.state.environment, (any: []) => {
- KubernetesAPI.setConfigMaps(any);
- });
- KaravanApi.getSecrets(this.state.environment, (any: []) => {
- KubernetesAPI.setSecrets(any);
- });
- KaravanApi.getServices(this.state.environment, (any: []) => {
- KubernetesAPI.setServices(any);
- });
+ if (!this.props.isTemplates){
+ KaravanApi.getConfigMaps(this.state.environment, (any: []) => {
+ KubernetesAPI.setConfigMaps(any);
+ });
+ KaravanApi.getSecrets(this.state.environment, (any: []) => {
+ KubernetesAPI.setSecrets(any);
+ });
+ KaravanApi.getServices(this.state.environment, (any: []) => {
+ KubernetesAPI.setServices(any);
+ });
+ }
}
}
@@ -401,10 +403,21 @@ export class ProjectPage extends React.Component<Props, State> {
}
getTemplatePanel() {
+ const {tab} = this.state;
return (
- <PageSection isFilled className="kamelets-page project-page-section" padding={{default: 'padding'}}>
- {this.getProjectFiles()}
- </PageSection>
+ <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
+ {/*<FlexItem className="project-tabs">*/}
+ {/* <Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>*/}
+ {/* <Tab eventKey="templates" title="Templates"/>*/}
+ {/* <Tab eventKey="kamelets" title="Kamelets"/>*/}
+ {/* </Tabs>*/}
+ {/*</FlexItem>*/}
+ <FlexItem>
+ <PageSection padding={{default: "padding"}}>
+ {this.getProjectFiles()}
+ </PageSection>
+ </FlexItem>
+ </Flex>
)
}
diff --git a/karavan-designer/src/kamelets/KameletsPage.tsx b/karavan-designer/src/kamelets/KameletsPage.tsx
index 0635917..1c500e4 100644
--- a/karavan-designer/src/kamelets/KameletsPage.tsx
+++ b/karavan-designer/src/kamelets/KameletsPage.tsx
@@ -21,7 +21,7 @@ import {
Gallery,
ToolbarItem,
TextInput,
- PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem, Badge, Button
+ PageSection, TextContent, Text, PageSectionVariants, Flex, FlexItem, Badge, Button, Switch
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {KameletCard} from "./KameletCard";
@@ -41,7 +41,8 @@ interface State {
repository: string,
path: string,
kamelets: KameletModel[],
- filter: string
+ filter: string,
+ customOnly: boolean
}
export class KameletsPage extends React.Component<Props, State> {
@@ -51,7 +52,8 @@ export class KameletsPage extends React.Component<Props, State> {
repository: '',
path: '',
kamelets: [],
- filter: ''
+ filter: '',
+ customOnly: false
};
componentDidMount() {
@@ -63,26 +65,26 @@ export class KameletsPage extends React.Component<Props, State> {
}
search(filter: string) {
- this.setState({
- filter: filter,
- isModalOpen: false,
- kamelets: KameletApi.getKamelets().filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()))
- })
+ this.setState({ filter: filter, isModalOpen: false})
}
render() {
+ const {dark, onRefresh} = this.props;
+ const {kamelets, kamelet, isModalOpen, customOnly, filter} = this.state;
+ let kameletList = kamelets.filter(kamelet => kamelet.spec.definition.title.toLowerCase().includes(filter.toLowerCase()));
+ if (customOnly) kameletList = kameletList.filter(k => KameletApi.getCustomKameletNames().includes(k.metadata.name));
return (
- <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}
+ <PageSection variant={dark ? PageSectionVariants.darker : PageSectionVariants.light}
padding={{default: 'noPadding'}} className="kamelet-section">
- <KameletModal key={this.state.kamelet?.metadata.name + this.state.isModalOpen.toString()}
- isOpen={this.state.isModalOpen} kamelet={this.state.kamelet}/>
+ <KameletModal key={kamelet?.metadata.name + isModalOpen.toString()}
+ isOpen={isModalOpen} kamelet={kamelet}/>
<PageSection className="tools-section"
- variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
+ variant={dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
<FlexItem>
<TextContent className="header">
<Text component="h2">Kamelet Catalog</Text>
- <Badge isRead className="labels">{this.state.kamelets.length}</Badge>
+ <Badge isRead className="labels">{kamelets.length}</Badge>
</TextContent>
</FlexItem>
<FlexItem>
@@ -91,14 +93,21 @@ export class KameletsPage extends React.Component<Props, State> {
<ToolbarItem>
<Button icon={<RefreshIcon/>} variant="link"
onClick={e => {
- this.props.onRefresh?.call(this).then(value => {
+ onRefresh?.call(this).then(value => {
this.setState({kamelets: KameletApi.getKamelets()});
})
}}/>
</ToolbarItem>
+ <ToolbarItem>
+ <Switch
+ label="Custom only"
+ isChecked={customOnly}
+ onChange={checked => this.setState({customOnly: checked})}
+ />
+ </ToolbarItem>
<ToolbarItem>
<TextInput className="text-field" type="search" id="search" name="search"
- value={this.state.filter}
+ value={filter}
onChange={value => this.search(value)}
autoComplete="off"
placeholder="Search by name"/>
@@ -109,9 +118,9 @@ export class KameletsPage extends React.Component<Props, State> {
</Flex>
</PageSection>
<PageSection isFilled className="kamelets-page"
- variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light}>
+ variant={dark ? PageSectionVariants.darker : PageSectionVariants.light}>
<Gallery hasGutter>
- {this.state.kamelets.map(k => (
+ {kameletList.map(k => (
<KameletCard key={k.metadata.name} kamelet={k} onClickCard={this.select}/>
))}
</Gallery>
[camel-karavan] 11/12: Templates and Kamelets project list
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 2bc3324a359a0f6d53769d1292307381080e6bb1
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 19:43:16 2022 -0500
Templates and Kamelets project list
---
.../apache/camel/karavan/api/ProjectResource.java | 10 +-
karavan-app/src/main/webui/src/Main.tsx | 9 +-
karavan-app/src/main/webui/src/api/KaravanApi.tsx | 11 -
.../src/main/webui/src/projects/ProjectsPage.tsx | 74 +----
.../main/webui/src/projects/ProjectsTableRow.tsx | 324 ++++-----------------
5 files changed, 74 insertions(+), 354 deletions(-)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
index c6620cf..77b2dc6 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
@@ -48,9 +48,13 @@ public class ProjectResource {
@Produces(MediaType.APPLICATION_JSON)
public List<Project> getAll() throws Exception {
return infinispanService.getProjects().stream()
- .filter(project -> !project.getProjectId().equalsIgnoreCase(Project.NAME_TEMPLATES))
- .filter(project -> !project.getProjectId().equalsIgnoreCase(Project.NAME_KAMELETS))
- .sorted(Comparator.comparing(Project::getProjectId))
+ .sorted((p1, p2) -> {
+ if (p1.getProjectId().equalsIgnoreCase(Project.NAME_TEMPLATES)) return 1;
+ if (p2.getProjectId().equalsIgnoreCase(Project.NAME_TEMPLATES)) return 1;
+ if (p1.getProjectId().equalsIgnoreCase(Project.NAME_KAMELETS)) return 1;
+ if (p2.getProjectId().equalsIgnoreCase(Project.NAME_KAMELETS)) return 1;
+ return (p1.getProjectId().compareTo(p2.getProjectId()));
+ })
.collect(Collectors.toList());
}
diff --git a/karavan-app/src/main/webui/src/Main.tsx b/karavan-app/src/main/webui/src/Main.tsx
index 5975cd2..95ebab2 100644
--- a/karavan-app/src/main/webui/src/Main.tsx
+++ b/karavan-app/src/main/webui/src/Main.tsx
@@ -66,7 +66,6 @@ interface State {
pageId: string,
projects: Project[],
project?: Project,
- templates?: Project,
isModalOpen: boolean,
projectToDelete?: Project,
openapi: string,
@@ -125,9 +124,6 @@ export class Main extends React.Component<Props, State> {
getData() {
KaravanApi.getConfiguration((config: any) => {
this.setState({config: config, request: uuidv4()});
- KaravanApi.getTemplatesProject((templates: Project) => {
- this.setState({templates: templates});
- });
});
this.updateKamelets();
this.updateComponents();
@@ -167,8 +163,7 @@ export class Main extends React.Component<Props, State> {
new MenuItem("projects", "Projects", <ProjectsIcon/>),
new MenuItem("eip", "Enterprise Integration Patterns", <EipIcon/>),
new MenuItem("kamelets", "Kamelets", <KameletsIcon/>),
- new MenuItem("components", "Components", <ComponentsIcon/>),
- new MenuItem("templates", "Templates", <PficonTemplateIcon/>)
+ new MenuItem("components", "Components", <ComponentsIcon/>)
]
return (<Flex className="nav-buttons" direction={{default: "column"}} style={{height: "100%"}}
spaceItems={{default: "spaceItemsNone"}}>
@@ -246,8 +241,6 @@ export class Main extends React.Component<Props, State> {
onSelect={this.onProjectSelect}
toast={this.toast}
config={this.state.config}/>}
- {this.state.pageId === 'templates' && this.state.templates &&
- <ProjectPage key="templates" project={this.state.templates} isTemplates={true} config={this.state.config}/>}
{this.state.pageId === 'kamelets' &&
<KameletsPage dark={false} onRefresh={this.updateKamelets}/>}
{this.state.pageId === 'components' &&
diff --git a/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index c446efb..78feec2 100644
--- a/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -277,17 +277,6 @@ export class KaravanApi {
});
}
- static async getTemplatesProject( after: (project: Project) => void) {
- instance.get('/api/template')
- .then(res => {
- if (res.status === 200) {
- after(res.data);
- }
- }).catch(err => {
- console.log(err);
- });
- }
-
static async getTemplatesFiles( after: (files: []) => void) {
instance.get('/api/template/files')
.then(res => {
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index fbb23d9..b3a274e 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -12,18 +12,12 @@ import {
FormGroup,
ModalVariant,
Form,
- Badge,
- Tooltip,
Bullseye,
EmptyState,
EmptyStateVariant,
EmptyStateIcon,
Title,
- OverflowMenu,
- OverflowMenuContent,
- OverflowMenuGroup,
- OverflowMenuItem,
- Flex, FlexItem, Radio, Spinner
+ Radio, Spinner
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {MainToolbar} from "../MainToolbar";
@@ -31,13 +25,12 @@ import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
import {DeploymentStatus, Project} from "./ProjectModels";
import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
-import CopyIcon from "@patternfly/react-icons/dist/esm/icons/copy-icon";
import {CamelUi} from "../designer/utils/CamelUi";
import {KaravanApi} from "../api/KaravanApi";
import {QuarkusIcon, SpringIcon} from "../designer/utils/KaravanIcons";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {ProjectsTableRow} from "./ProjectsTableRow";
interface Props {
config: any,
@@ -240,14 +233,6 @@ export class ProjectsPage extends React.Component<Props, State> {
return this.props.config.environments && Array.isArray(this.props.config.environments) ? Array.from(this.props.config.environments) : [];
}
- getDeploymentByEnvironments(name: string): [string, DeploymentStatus | undefined] [] {
- const deps = this.state.deploymentStatuses;
- return this.getEnvironments().map(e => {
- const env: string = e as string;
- const dep = deps.find(d => d.name === name && d.env === env);
- return [env, dep];
- });
- }
getEmptyState() {
const {loading} = this.state;
@@ -270,6 +255,7 @@ export class ProjectsPage extends React.Component<Props, State> {
)
}
+
getProjectsTable() {
const {projects, filter} = this.state;
const projs = projects.filter(p => p.name.toLowerCase().includes(filter) || p.description.toLowerCase().includes(filter));
@@ -288,53 +274,12 @@ export class ProjectsPage extends React.Component<Props, State> {
</Thead>
<Tbody>
{projs.map(project => (
- <Tr key={project.projectId}>
- <Td modifier={"fitContent"}>
- <Tooltip content={project.runtime} position={"left"}>
- <Badge className="runtime-badge">{project.runtime.substring(0, 1).toUpperCase()}</Badge>
- </Tooltip>
- </Td>
- <Td>
- <Button style={{padding: '6px'}} variant={"link"} onClick={e => this.props.onSelect?.call(this, project)}>
- {project.projectId}
- </Button>
- </Td>
- <Td>{project.name}</Td>
- <Td>{project.description}</Td>
- <Td isActionCell>
- <Tooltip content={project.lastCommit} position={"bottom"}>
- <Badge>{project.lastCommit?.substr(0, 7)}</Badge>
- </Tooltip>
- </Td>
- <Td noPadding style={{width: "180px"}}>
- <Flex direction={{default: "row"}}>
- {this.getDeploymentByEnvironments(project.projectId).map(value => (
- <FlexItem className="badge-flex-item" key={value[0]}>
- <Badge className="badge" isRead={!value[1]}>{value[0]}</Badge>
- </FlexItem>
- ))}
- </Flex>
- </Td>
- <Td isActionCell>
- <OverflowMenu breakpoint="md">
- <OverflowMenuContent>
- <OverflowMenuGroup groupType="button">
- <OverflowMenuItem>
- <Tooltip content={"Copy project"} position={"bottom"}>
- <Button variant={"plain"} icon={<CopyIcon/>}
- onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
- </Tooltip>
- </OverflowMenuItem>
- <OverflowMenuItem>
- <Tooltip content={"Delete project"} position={"bottom"}>
- <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => this.onProjectDelete(project)}></Button>
- </Tooltip>
- </OverflowMenuItem>
- </OverflowMenuGroup>
- </OverflowMenuContent>
- </OverflowMenu>
- </Td>
- </Tr>
+ <ProjectsTableRow
+ config={this.props.config}
+ onSelect={this.props.onSelect}
+ onProjectDelete={this.onProjectDelete}
+ project={project}
+ deploymentStatuses={this.state.deploymentStatuses}/>
))}
{projs.length === 0 && this.getEmptyState()}
</Tbody>
@@ -343,7 +288,6 @@ export class ProjectsPage extends React.Component<Props, State> {
}
render() {
- const projects = this.state.projects.filter(p => p.name.toLowerCase().includes(this.state.filter) || p.description.toLowerCase().includes(this.state.filter));
return (
<PageSection className="kamelet-section projects-page" padding={{default: 'noPadding'}}>
<PageSection className="tools-section" padding={{default: 'noPadding'}}>
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
index a3be55d..86723b5 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
@@ -42,7 +42,9 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
interface Props {
config: any,
onSelect: (project: Project) => void
- toast: (title: string, text: string, variant: 'success' | 'danger' | 'warning' | 'info' | 'default') => void
+ onProjectDelete: (project: Project) => void
+ project: Project
+ deploymentStatuses: DeploymentStatus[],
}
interface State {
@@ -61,7 +63,7 @@ interface State {
runtime: string,
}
-export class ProjectsPage extends React.Component<Props, State> {
+export class ProjectsTableRow extends React.Component<Props, State> {
public state: State = {
projects: [],
@@ -76,165 +78,6 @@ export class ProjectsPage extends React.Component<Props, State> {
projectId: '',
runtime: this.props.config.runtime
};
- interval: any;
-
- componentDidMount() {
- this.interval = setInterval(() => this.onGetProjects(), 1300);
- }
-
- componentWillUnmount() {
- clearInterval(this.interval);
- }
-
- onProjectDelete = (project: Project) => {
- this.setState({isDeleteModalOpen: true, projectToDelete: project})
- };
-
-
- deleteProject = () => {
- if (this.state.projectToDelete)
- KaravanApi.deleteProject(this.state.projectToDelete, res => {
- if (res.status === 204) {
- this.props.toast?.call(this, "Success", "Project deleted", "success");
- this.onGetProjects();
- } else {
- this.props.toast?.call(this, "Error", res.statusText, "danger");
- }
- });
- this.setState({isDeleteModalOpen: false})
- }
-
- onProjectCreate = (project: Project) => {
- KaravanApi.postProject(project, res => {
- console.log(res.status)
- if (res.status === 200 || res.status === 201) {
- this.props.toast?.call(this, "Success", "Project created", "success");
- } else {
- this.props.toast?.call(this, "Error", res.status + ", " + res.statusText, "danger");
- }
- });
- };
-
- onGetProjects = () => {
- this.setState({loading: true});
- KaravanApi.getProjects((projects: Project[]) => {
- this.setState({projects: projects, loading: false})
- });
- KaravanApi.getDeploymentStatuses(this.props.config.environment, (statuses: DeploymentStatus[]) => {
- this.setState({deploymentStatuses: statuses});
- });
- }
-
- tools = () => (<Toolbar id="toolbar-group-types">
- <ToolbarContent>
- <ToolbarItem>
- <Button variant="link" icon={<RefreshIcon/>} onClick={e => this.onGetProjects()}/>
- </ToolbarItem>
- <ToolbarItem>
- <TextInput className="text-field" type="search" id="search" name="search"
- autoComplete="off" placeholder="Search by name"
- value={this.state.filter}
- onChange={e => this.setState({filter: e})}/>
- </ToolbarItem>
- <ToolbarItem>
- <Button icon={<PlusIcon/>} onClick={e => this.setState({isCreateModalOpen: true, isCopy: false})}>Create</Button>
- </ToolbarItem>
- </ToolbarContent>
- </Toolbar>);
-
- title = () => (<TextContent>
- <Text component="h2">Projects</Text>
- </TextContent>);
-
- closeModal = () => {
- this.setState({isCreateModalOpen: false, isCopy: false, name: this.props.config.groupId, description: '', projectId: '', runtime: this.props.config.runtime});
- this.onGetProjects();
- }
-
- saveAndCloseCreateModal = () => {
- const {name, description, projectId, runtime} = this.state;
- const p = new Project(projectId, name, description, runtime, '');
- this.onProjectCreate(p);
- this.setState({isCreateModalOpen: false, isCopy: false, name: this.props.config.groupId, description: '', projectId: ''});
- }
-
- onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
- if (event.key === 'Enter' && this.state.name !== undefined && this.state.description !== undefined && this.state.projectId !== undefined) {
- this.saveAndCloseCreateModal();
- }
- }
-
- createModalForm() {
- const {isCopy, projectToCopy, projectId, name, isCreateModalOpen, description, runtime} = this.state;
- const {runtimes} = this.props.config;
- const isReady = projectId && name && description && !['templates', 'kamelets'].includes(projectId);
- return (
- <Modal
- title={!isCopy ? "Create new project" : "Copy project from " + projectToCopy?.projectId}
- variant={ModalVariant.small}
- isOpen={isCreateModalOpen}
- onClose={this.closeModal}
- onKeyDown={this.onKeyDown}
- actions={[
- <Button key="confirm" variant="primary" isDisabled={!isReady} onClick={this.saveAndCloseCreateModal}>Save</Button>,
- <Button key="cancel" variant="secondary" onClick={this.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 => this.setState({name: e})}/>
- </FormGroup>
- <FormGroup label="Description" fieldId="description" isRequired>
- <TextInput className="text-field" type="text" id="description" name="description"
- value={description}
- onChange={e => this.setState({description: e})}/>
- </FormGroup>
- <FormGroup label="Project ID" fieldId="projectId" isRequired helperText="Unique project name">
- <TextInput className="text-field" type="text" id="projectId" name="projectId"
- value={projectId}
- onFocus={e => this.setState({projectId: projectId === '' ? CamelUi.nameFromTitle(name) : projectId})}
- onChange={e => this.setState({projectId: CamelUi.nameFromTitle(e)})}/>
- </FormGroup>
- <FormGroup label="Runtime" fieldId="runtime" isRequired>
- {runtimes?.map((r: string) => (
- <Radio key={r} id={r} name={r} className="radio"
- isChecked={r === runtime}
- onChange={checked => {
- if (checked) this.setState({runtime: r})
- }}
- body={
- <div className="runtime-radio">
- {runtime === 'quarkus' ? QuarkusIcon() : SpringIcon()}
- <div className="runtime-label">{CamelUtil.capitalizeName(r)}</div>
- </div>}
- />
- ))}
- </FormGroup>
- </Form>
- </Modal>
- )
- }
-
- deleteModalForm() {
- return (
- <Modal
- title="Confirmation"
- variant={ModalVariant.small}
- isOpen={this.state.isDeleteModalOpen}
- onClose={() => this.setState({isDeleteModalOpen: false})}
- actions={[
- <Button key="confirm" variant="primary" onClick={e => this.deleteProject()}>Delete</Button>,
- <Button key="cancel" variant="link"
- onClick={e => this.setState({isDeleteModalOpen: false})}>Cancel</Button>
- ]}
- onEscapePress={e => this.setState({isDeleteModalOpen: false})}>
- <div>{"Are you sure you want to delete the project " + this.state.projectToDelete?.projectId + "?"}</div>
- </Modal>
- )
- }
getEnvironments(): string [] {
return this.props.config.environments && Array.isArray(this.props.config.environments) ? Array.from(this.props.config.environments) : [];
@@ -249,115 +92,62 @@ export class ProjectsPage extends React.Component<Props, State> {
});
}
- getEmptyState() {
- const {loading} = this.state;
+ render() {
+ const {project, onProjectDelete, onSelect} = this.props;
+ const isBuildIn = ['kamelets', 'templates'].includes(project.projectId);
+ const badge = isBuildIn ? project.projectId.toUpperCase().charAt(0) : project.runtime.substring(0, 1).toUpperCase();
return (
- <Tr>
- <Td colSpan={8}>
- <Bullseye>
- {loading && <Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>}
- {!loading &&
- <EmptyState variant={EmptyStateVariant.small}>
- <EmptyStateIcon icon={SearchIcon}/>
- <Title headingLevel="h2" size="lg">
- No results found
- </Title>
- </EmptyState>
- }
- </Bullseye>
+ <Tr key={project.projectId}>
+ <Td modifier={"fitContent"}>
+ <Tooltip content={project.runtime} position={"left"}>
+ <Badge isRead={isBuildIn} className="runtime-badge">{badge}</Badge>
+ </Tooltip>
+ </Td>
+ <Td>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={e => onSelect?.call(this, project)}>
+ {project.projectId}
+ </Button>
+ </Td>
+ <Td>{project.name}</Td>
+ <Td>{project.description}</Td>
+ <Td isActionCell>
+ <Tooltip content={project.lastCommit} position={"bottom"}>
+ <Badge>{project.lastCommit?.substr(0, 7)}</Badge>
+ </Tooltip>
+ </Td>
+ <Td noPadding style={{width: "180px"}}>
+ {!isBuildIn &&
+ <Flex direction={{default: "row"}}>
+ {this.getDeploymentByEnvironments(project.projectId).map(value => (
+ <FlexItem className="badge-flex-item" key={value[0]}>
+ <Badge className="badge" isRead={!value[1]}>{value[0]}</Badge>
+ </FlexItem>
+ ))}
+ </Flex>
+ }
+ </Td>
+ <Td isActionCell>
+ {!isBuildIn &&
+ <OverflowMenu breakpoint="md">
+ <OverflowMenuContent>
+ <OverflowMenuGroup groupType="button">
+ <OverflowMenuItem>
+ <Tooltip content={"Copy project"} position={"bottom"}>
+ <Button variant={"plain"} icon={<CopyIcon/>}
+ onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
+ </Tooltip>
+ </OverflowMenuItem>
+ <OverflowMenuItem>
+ <Tooltip content={"Delete project"} position={"bottom"}>
+ <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => onProjectDelete.call(this, project)}></Button>
+ </Tooltip>
+ </OverflowMenuItem>
+ </OverflowMenuGroup>
+ </OverflowMenuContent>
+ </OverflowMenu>
+ }
</Td>
</Tr>
)
}
-
- isBuildIn(project: Project): boolean {
- return ['kamelets', 'templates'].includes(project.projectId);
- }
-
- getProjectsTable() {
- const {projects, filter} = this.state;
- const projs = projects.filter(p => p.name.toLowerCase().includes(filter) || p.description.toLowerCase().includes(filter));
- return (
- <TableComposable aria-label="Projects" variant={"compact"}>
- <Thead>
- <Tr>
- <Th key='type'>Runtime</Th>
- <Th key='projectId'>Project ID</Th>
- <Th key='name'>Name</Th>
- <Th key='description'>Description</Th>
- <Th key='commit'>Commit</Th>
- <Th key='deployment'>Environment</Th>
- <Th key='action'></Th>
- </Tr>
- </Thead>
- <Tbody>
- {projs.map(project => (
- <Tr key={project.projectId}>
- <Td modifier={"fitContent"}>
- <Tooltip content={project.runtime} position={"left"}>
- <Badge className="runtime-badge">{project.runtime.substring(0, 1).toUpperCase()}</Badge>
- </Tooltip>
- </Td>
- <Td>
- <Button style={{padding: '6px'}} variant={"link"} onClick={e => this.props.onSelect?.call(this, project)}>
- {project.projectId}
- </Button>
- </Td>
- <Td>{project.name}</Td>
- <Td>{project.description}</Td>
- <Td isActionCell>
- <Tooltip content={project.lastCommit} position={"bottom"}>
- <Badge>{project.lastCommit?.substr(0, 7)}</Badge>
- </Tooltip>
- </Td>
- <Td noPadding style={{width: "180px"}}>
- <Flex direction={{default: "row"}}>
- {this.getDeploymentByEnvironments(project.projectId).map(value => (
- <FlexItem className="badge-flex-item" key={value[0]}>
- <Badge className="badge" isRead={!value[1]}>{value[0]}</Badge>
- </FlexItem>
- ))}
- </Flex>
- </Td>
- <Td isActionCell>
- <OverflowMenu breakpoint="md">
- <OverflowMenuContent>
- <OverflowMenuGroup groupType="button">
- <OverflowMenuItem>
- <Tooltip content={"Copy project"} position={"bottom"}>
- <Button variant={"plain"} icon={<CopyIcon/>}
- onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
- </Tooltip>
- </OverflowMenuItem>
- <OverflowMenuItem>
- <Tooltip content={"Delete project"} position={"bottom"}>
- <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => this.onProjectDelete(project)}></Button>
- </Tooltip>
- </OverflowMenuItem>
- </OverflowMenuGroup>
- </OverflowMenuContent>
- </OverflowMenu>
- </Td>
- </Tr>
- ))}
- {projs.length === 0 && this.getEmptyState()}
- </Tbody>
- </TableComposable>
- )
- }
-
- render() {
- return (
- <PageSection className="kamelet-section projects-page" padding={{default: 'noPadding'}}>
- <PageSection className="tools-section" padding={{default: 'noPadding'}}>
- <MainToolbar title={this.title()} tools={this.tools()}/>
- </PageSection>
- <PageSection isFilled className="kamelets-page">
- {this.getProjectsTable()}
- </PageSection>
- {this.createModalForm()}
- {this.deleteModalForm()}
- </PageSection>
- )
- }
}
\ No newline at end of file
[camel-karavan] 10/12: Templates and Kamelets project list
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit e60eba696e5094480a67b99307f2a21973885d09
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 19:43:10 2022 -0500
Templates and Kamelets project list
---
.../apache/camel/karavan/api/TemplateResource.java | 61 ----
.../main/webui/src/projects/ProjectsTableRow.tsx | 363 +++++++++++++++++++++
2 files changed, 363 insertions(+), 61 deletions(-)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/TemplateResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/TemplateResource.java
deleted file mode 100644
index 2be7c7e..0000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/TemplateResource.java
+++ /dev/null
@@ -1,61 +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.
- */
-package org.apache.camel.karavan.api;
-
-import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.model.ProjectFile;
-import org.apache.camel.karavan.service.InfinispanService;
-
-import javax.inject.Inject;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-
-@Path("/api/template")
-public class TemplateResource {
-
- @Inject
- InfinispanService infinispanService;
-
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- public Project get() throws Exception {
- return infinispanService.getProject(Project.NAME_TEMPLATES);
- }
-
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/files")
- public List<ProjectFile> getFiles() throws Exception {
- return infinispanService.getProjectFiles(Project.NAME_TEMPLATES);
- }
-
- @POST
- @Produces(MediaType.APPLICATION_JSON)
- @Consumes(MediaType.APPLICATION_JSON)
- public ProjectFile save(ProjectFile file) throws Exception {
- if (file.getProjectId().equalsIgnoreCase(Project.NAME_TEMPLATES)){
- infinispanService.saveProjectFile(file);
- }
- return file;
- }
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
new file mode 100644
index 0000000..a3be55d
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
@@ -0,0 +1,363 @@
+import React from 'react';
+import {
+ Toolbar,
+ ToolbarContent,
+ ToolbarItem,
+ TextInput,
+ PageSection,
+ TextContent,
+ Text,
+ Button,
+ Modal,
+ FormGroup,
+ ModalVariant,
+ Form,
+ Badge,
+ Tooltip,
+ Bullseye,
+ EmptyState,
+ EmptyStateVariant,
+ EmptyStateIcon,
+ Title,
+ OverflowMenu,
+ OverflowMenuContent,
+ OverflowMenuGroup,
+ OverflowMenuItem,
+ Flex, FlexItem, Radio, Spinner
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {MainToolbar} from "../MainToolbar";
+import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
+import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
+import {DeploymentStatus, Project} from "./ProjectModels";
+import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
+import CopyIcon from "@patternfly/react-icons/dist/esm/icons/copy-icon";
+import {CamelUi} from "../designer/utils/CamelUi";
+import {KaravanApi} from "../api/KaravanApi";
+import {QuarkusIcon, SpringIcon} from "../designer/utils/KaravanIcons";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+
+interface Props {
+ config: any,
+ onSelect: (project: Project) => void
+ toast: (title: string, text: string, variant: 'success' | 'danger' | 'warning' | 'info' | 'default') => void
+}
+
+interface State {
+ projects: Project[],
+ deploymentStatuses: DeploymentStatus[],
+ isCreateModalOpen: boolean,
+ isDeleteModalOpen: boolean,
+ isCopy: boolean,
+ loading: boolean,
+ projectToCopy?: Project,
+ projectToDelete?: Project,
+ filter: string,
+ name: string,
+ description: string,
+ projectId: string,
+ runtime: string,
+}
+
+export class ProjectsPage extends React.Component<Props, State> {
+
+ public state: State = {
+ projects: [],
+ deploymentStatuses: [],
+ isCreateModalOpen: false,
+ isDeleteModalOpen: false,
+ isCopy: false,
+ loading: true,
+ filter: '',
+ name: '',
+ description: '',
+ projectId: '',
+ runtime: this.props.config.runtime
+ };
+ interval: any;
+
+ componentDidMount() {
+ this.interval = setInterval(() => this.onGetProjects(), 1300);
+ }
+
+ componentWillUnmount() {
+ clearInterval(this.interval);
+ }
+
+ onProjectDelete = (project: Project) => {
+ this.setState({isDeleteModalOpen: true, projectToDelete: project})
+ };
+
+
+ deleteProject = () => {
+ if (this.state.projectToDelete)
+ KaravanApi.deleteProject(this.state.projectToDelete, res => {
+ if (res.status === 204) {
+ this.props.toast?.call(this, "Success", "Project deleted", "success");
+ this.onGetProjects();
+ } else {
+ this.props.toast?.call(this, "Error", res.statusText, "danger");
+ }
+ });
+ this.setState({isDeleteModalOpen: false})
+ }
+
+ onProjectCreate = (project: Project) => {
+ KaravanApi.postProject(project, res => {
+ console.log(res.status)
+ if (res.status === 200 || res.status === 201) {
+ this.props.toast?.call(this, "Success", "Project created", "success");
+ } else {
+ this.props.toast?.call(this, "Error", res.status + ", " + res.statusText, "danger");
+ }
+ });
+ };
+
+ onGetProjects = () => {
+ this.setState({loading: true});
+ KaravanApi.getProjects((projects: Project[]) => {
+ this.setState({projects: projects, loading: false})
+ });
+ KaravanApi.getDeploymentStatuses(this.props.config.environment, (statuses: DeploymentStatus[]) => {
+ this.setState({deploymentStatuses: statuses});
+ });
+ }
+
+ tools = () => (<Toolbar id="toolbar-group-types">
+ <ToolbarContent>
+ <ToolbarItem>
+ <Button variant="link" icon={<RefreshIcon/>} onClick={e => this.onGetProjects()}/>
+ </ToolbarItem>
+ <ToolbarItem>
+ <TextInput className="text-field" type="search" id="search" name="search"
+ autoComplete="off" placeholder="Search by name"
+ value={this.state.filter}
+ onChange={e => this.setState({filter: e})}/>
+ </ToolbarItem>
+ <ToolbarItem>
+ <Button icon={<PlusIcon/>} onClick={e => this.setState({isCreateModalOpen: true, isCopy: false})}>Create</Button>
+ </ToolbarItem>
+ </ToolbarContent>
+ </Toolbar>);
+
+ title = () => (<TextContent>
+ <Text component="h2">Projects</Text>
+ </TextContent>);
+
+ closeModal = () => {
+ this.setState({isCreateModalOpen: false, isCopy: false, name: this.props.config.groupId, description: '', projectId: '', runtime: this.props.config.runtime});
+ this.onGetProjects();
+ }
+
+ saveAndCloseCreateModal = () => {
+ const {name, description, projectId, runtime} = this.state;
+ const p = new Project(projectId, name, description, runtime, '');
+ this.onProjectCreate(p);
+ this.setState({isCreateModalOpen: false, isCopy: false, name: this.props.config.groupId, description: '', projectId: ''});
+ }
+
+ onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
+ if (event.key === 'Enter' && this.state.name !== undefined && this.state.description !== undefined && this.state.projectId !== undefined) {
+ this.saveAndCloseCreateModal();
+ }
+ }
+
+ createModalForm() {
+ const {isCopy, projectToCopy, projectId, name, isCreateModalOpen, description, runtime} = this.state;
+ const {runtimes} = this.props.config;
+ const isReady = projectId && name && description && !['templates', 'kamelets'].includes(projectId);
+ return (
+ <Modal
+ title={!isCopy ? "Create new project" : "Copy project from " + projectToCopy?.projectId}
+ variant={ModalVariant.small}
+ isOpen={isCreateModalOpen}
+ onClose={this.closeModal}
+ onKeyDown={this.onKeyDown}
+ actions={[
+ <Button key="confirm" variant="primary" isDisabled={!isReady} onClick={this.saveAndCloseCreateModal}>Save</Button>,
+ <Button key="cancel" variant="secondary" onClick={this.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 => this.setState({name: e})}/>
+ </FormGroup>
+ <FormGroup label="Description" fieldId="description" isRequired>
+ <TextInput className="text-field" type="text" id="description" name="description"
+ value={description}
+ onChange={e => this.setState({description: e})}/>
+ </FormGroup>
+ <FormGroup label="Project ID" fieldId="projectId" isRequired helperText="Unique project name">
+ <TextInput className="text-field" type="text" id="projectId" name="projectId"
+ value={projectId}
+ onFocus={e => this.setState({projectId: projectId === '' ? CamelUi.nameFromTitle(name) : projectId})}
+ onChange={e => this.setState({projectId: CamelUi.nameFromTitle(e)})}/>
+ </FormGroup>
+ <FormGroup label="Runtime" fieldId="runtime" isRequired>
+ {runtimes?.map((r: string) => (
+ <Radio key={r} id={r} name={r} className="radio"
+ isChecked={r === runtime}
+ onChange={checked => {
+ if (checked) this.setState({runtime: r})
+ }}
+ body={
+ <div className="runtime-radio">
+ {runtime === 'quarkus' ? QuarkusIcon() : SpringIcon()}
+ <div className="runtime-label">{CamelUtil.capitalizeName(r)}</div>
+ </div>}
+ />
+ ))}
+ </FormGroup>
+ </Form>
+ </Modal>
+ )
+ }
+
+ deleteModalForm() {
+ return (
+ <Modal
+ title="Confirmation"
+ variant={ModalVariant.small}
+ isOpen={this.state.isDeleteModalOpen}
+ onClose={() => this.setState({isDeleteModalOpen: false})}
+ actions={[
+ <Button key="confirm" variant="primary" onClick={e => this.deleteProject()}>Delete</Button>,
+ <Button key="cancel" variant="link"
+ onClick={e => this.setState({isDeleteModalOpen: false})}>Cancel</Button>
+ ]}
+ onEscapePress={e => this.setState({isDeleteModalOpen: false})}>
+ <div>{"Are you sure you want to delete the project " + this.state.projectToDelete?.projectId + "?"}</div>
+ </Modal>
+ )
+ }
+
+ getEnvironments(): string [] {
+ return this.props.config.environments && Array.isArray(this.props.config.environments) ? Array.from(this.props.config.environments) : [];
+ }
+
+ getDeploymentByEnvironments(name: string): [string, DeploymentStatus | undefined] [] {
+ const deps = this.state.deploymentStatuses;
+ return this.getEnvironments().map(e => {
+ const env: string = e as string;
+ const dep = deps.find(d => d.name === name && d.env === env);
+ return [env, dep];
+ });
+ }
+
+ getEmptyState() {
+ const {loading} = this.state;
+ return (
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ {loading && <Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>}
+ {!loading &&
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={SearchIcon}/>
+ <Title headingLevel="h2" size="lg">
+ No results found
+ </Title>
+ </EmptyState>
+ }
+ </Bullseye>
+ </Td>
+ </Tr>
+ )
+ }
+
+ isBuildIn(project: Project): boolean {
+ return ['kamelets', 'templates'].includes(project.projectId);
+ }
+
+ getProjectsTable() {
+ const {projects, filter} = this.state;
+ const projs = projects.filter(p => p.name.toLowerCase().includes(filter) || p.description.toLowerCase().includes(filter));
+ return (
+ <TableComposable aria-label="Projects" variant={"compact"}>
+ <Thead>
+ <Tr>
+ <Th key='type'>Runtime</Th>
+ <Th key='projectId'>Project ID</Th>
+ <Th key='name'>Name</Th>
+ <Th key='description'>Description</Th>
+ <Th key='commit'>Commit</Th>
+ <Th key='deployment'>Environment</Th>
+ <Th key='action'></Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {projs.map(project => (
+ <Tr key={project.projectId}>
+ <Td modifier={"fitContent"}>
+ <Tooltip content={project.runtime} position={"left"}>
+ <Badge className="runtime-badge">{project.runtime.substring(0, 1).toUpperCase()}</Badge>
+ </Tooltip>
+ </Td>
+ <Td>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={e => this.props.onSelect?.call(this, project)}>
+ {project.projectId}
+ </Button>
+ </Td>
+ <Td>{project.name}</Td>
+ <Td>{project.description}</Td>
+ <Td isActionCell>
+ <Tooltip content={project.lastCommit} position={"bottom"}>
+ <Badge>{project.lastCommit?.substr(0, 7)}</Badge>
+ </Tooltip>
+ </Td>
+ <Td noPadding style={{width: "180px"}}>
+ <Flex direction={{default: "row"}}>
+ {this.getDeploymentByEnvironments(project.projectId).map(value => (
+ <FlexItem className="badge-flex-item" key={value[0]}>
+ <Badge className="badge" isRead={!value[1]}>{value[0]}</Badge>
+ </FlexItem>
+ ))}
+ </Flex>
+ </Td>
+ <Td isActionCell>
+ <OverflowMenu breakpoint="md">
+ <OverflowMenuContent>
+ <OverflowMenuGroup groupType="button">
+ <OverflowMenuItem>
+ <Tooltip content={"Copy project"} position={"bottom"}>
+ <Button variant={"plain"} icon={<CopyIcon/>}
+ onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
+ </Tooltip>
+ </OverflowMenuItem>
+ <OverflowMenuItem>
+ <Tooltip content={"Delete project"} position={"bottom"}>
+ <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => this.onProjectDelete(project)}></Button>
+ </Tooltip>
+ </OverflowMenuItem>
+ </OverflowMenuGroup>
+ </OverflowMenuContent>
+ </OverflowMenu>
+ </Td>
+ </Tr>
+ ))}
+ {projs.length === 0 && this.getEmptyState()}
+ </Tbody>
+ </TableComposable>
+ )
+ }
+
+ render() {
+ return (
+ <PageSection className="kamelet-section projects-page" padding={{default: 'noPadding'}}>
+ <PageSection className="tools-section" padding={{default: 'noPadding'}}>
+ <MainToolbar title={this.title()} tools={this.tools()}/>
+ </PageSection>
+ <PageSection isFilled className="kamelets-page">
+ {this.getProjectsTable()}
+ </PageSection>
+ {this.createModalForm()}
+ {this.deleteModalForm()}
+ </PageSection>
+ )
+ }
+}
\ No newline at end of file
[camel-karavan] 04/12: Align Look and feel
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit f1382d702f6ae8b9cd15f5c7478d3bcd3fb1b4a4
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 17:05:42 2022 -0500
Align Look and feel
---
.../src/main/webui/src/dashboard/DashboardPage.tsx | 35 +++-
.../src/main/webui/src/designer/karavan.css | 1 +
karavan-app/src/main/webui/src/index.css | 14 +-
.../src/main/webui/src/projects/ProjectPage.tsx | 4 +-
.../src/main/webui/src/projects/ProjectsPage.tsx | 181 ++++++++++++---------
karavan-designer/src/designer/karavan.css | 1 +
6 files changed, 135 insertions(+), 101 deletions(-)
diff --git a/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx b/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
index 8f5fe20..e1e5ced 100644
--- a/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
+++ b/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
@@ -1,13 +1,13 @@
import React from 'react';
import {
- Badge,
- Button,
+ Badge, Bullseye,
+ Button, EmptyState, EmptyStateIcon, EmptyStateVariant,
Flex,
FlexItem, HelperText, HelperTextItem, Label, LabelGroup,
- PageSection,
+ PageSection, Spinner,
Text,
TextContent,
- TextInput, ToggleGroup, ToggleGroupItem,
+ TextInput, Title, ToggleGroup, ToggleGroupItem,
Toolbar,
ToolbarContent,
ToolbarItem, Tooltip
@@ -22,6 +22,7 @@ import Icon from "../Logo";
import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon";
+import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
interface Props {
config: any,
@@ -37,6 +38,7 @@ interface State {
isCreateModalOpen: boolean,
isDeleteModalOpen: boolean,
isCopy: boolean,
+ loading: boolean,
projectToCopy?: Project,
projectToDelete?: Project,
filter: string,
@@ -56,6 +58,7 @@ export class DashboardPage extends React.Component<Props, State> {
isCreateModalOpen: false,
isDeleteModalOpen: false,
isCopy: false,
+ loading: true,
filter: '',
name: '',
description: '',
@@ -75,7 +78,7 @@ export class DashboardPage extends React.Component<Props, State> {
onGetProjects = () => {
KaravanApi.getConfiguration((config: any) => {
KaravanApi.getProjects((projects: Project[]) => {
- this.setState({projects: projects})
+ this.setState({projects: projects, loading: false})
});
KaravanApi.getAllDeploymentStatuses((statuses: DeploymentStatus[]) => {
this.setState({deploymentStatuses: statuses});
@@ -223,6 +226,27 @@ export class DashboardPage extends React.Component<Props, State> {
}
}
+ getEmptyState() {
+ const {loading} = this.state;
+ return (
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ {loading && <Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>}
+ {!loading &&
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={SearchIcon}/>
+ <Title headingLevel="h2" size="lg">
+ No results found
+ </Title>
+ </EmptyState>
+ }
+ </Bullseye>
+ </Td>
+ </Tr>
+ )
+ }
+
render() {
const deployments = Array.from(new Set(this.state.deploymentStatuses.filter(d => d.name.toLowerCase().includes(this.state.filter)).map(d => d.name)));
return (
@@ -315,6 +339,7 @@ export class DashboardPage extends React.Component<Props, State> {
</Td>
</Tr>
))}
+ {deployments.length === 0 && this.getEmptyState()}
</Tbody>
</TableComposable>
</PageSection>
diff --git a/karavan-app/src/main/webui/src/designer/karavan.css b/karavan-app/src/main/webui/src/designer/karavan.css
index 38e2973..77ff41e 100644
--- a/karavan-app/src/main/webui/src/designer/karavan.css
+++ b/karavan-app/src/main/webui/src/designer/karavan.css
@@ -1274,6 +1274,7 @@
overflow: auto;
flex-shrink: unset;
flex-grow: 1;
+ background-color: var(--pf-global--BackgroundColor--light-300);
}
.karavan .designer-page {
diff --git a/karavan-app/src/main/webui/src/index.css b/karavan-app/src/main/webui/src/index.css
index b19e0f5..efa6238 100644
--- a/karavan-app/src/main/webui/src/index.css
+++ b/karavan-app/src/main/webui/src/index.css
@@ -68,18 +68,6 @@
background-color: var(--pf-global--BackgroundColor--dark-400);
}
-.karavan .kamelet-section {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.karavan .kamelets-page {
- overflow: auto;
- flex-shrink: unset;
- flex-grow: 1;
-}
-
.karavan .integration-card .pf-c-card__footer {
text-align: end;
}
@@ -128,7 +116,7 @@
font-size: 14px;
}
-.karavan .project-page .project-page-section {
+.karavan .project-page .project-tabs {
background-color: white;
}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
index e09b981..e1edd56 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectPage.tsx
@@ -420,7 +420,7 @@ export class ProjectPage extends React.Component<Props, State> {
padding={{default: file !== undefined ? 'noPadding' : 'noPadding'}}>
<Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
{!isTemplates &&
- <FlexItem>
+ <FlexItem className="project-tabs">
<Tabs activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex})}>
<Tab eventKey="development" title="Development"/>
<Tab eventKey="operations" title="Operations"/>
@@ -431,12 +431,12 @@ export class ProjectPage extends React.Component<Props, State> {
<FlexItem>
<PageSection padding={{default: "padding"}}>
{tab === 'development' && <ProjectInfo project={this.props.project} config={this.props.config} deleteEntity={this.deleteEntity} showLog={this.showLogs}/>}
+ {tab === 'development' && this.getProjectFiles()}
{tab === 'operations' && <ProjectOperations environments={this.state.environments} project={this.props.project} config={this.props.config}/>}
</PageSection>
</FlexItem>
}
</Flex>
- {tab === 'development' && this.getProjectFiles()}
</PageSection>}
{showDesigner && this.getDesigner()}
{showEditor && this.getEditor()}
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index 32a7a4d..320be76 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -23,7 +23,7 @@ import {
OverflowMenuContent,
OverflowMenuGroup,
OverflowMenuItem,
- Flex, FlexItem, Radio
+ Flex, FlexItem, Radio, Spinner
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {MainToolbar} from "../MainToolbar";
@@ -51,6 +51,7 @@ interface State {
isCreateModalOpen: boolean,
isDeleteModalOpen: boolean,
isCopy: boolean,
+ loading: boolean,
projectToCopy?: Project,
projectToDelete?: Project,
filter: string,
@@ -68,6 +69,7 @@ export class ProjectsPage extends React.Component<Props, State> {
isCreateModalOpen: false,
isDeleteModalOpen: false,
isCopy: false,
+ loading: true,
filter: '',
name: '',
description: '',
@@ -114,8 +116,9 @@ export class ProjectsPage extends React.Component<Props, State> {
};
onGetProjects = () => {
+ this.setState({loading: true});
KaravanApi.getProjects((projects: Project[]) => {
- this.setState({projects: projects})
+ this.setState({projects: projects, loading: false})
});
KaravanApi.getDeploymentStatuses(this.props.config.environment, (statuses: DeploymentStatus[]) => {
this.setState({deploymentStatuses: statuses});
@@ -144,7 +147,7 @@ export class ProjectsPage extends React.Component<Props, State> {
</TextContent>);
closeModal = () => {
- this.setState({isCreateModalOpen: false, isCopy: false, name: this.props.config.groupId, description: '', projectId: '', runtime: this.props.config.runtime });
+ this.setState({isCreateModalOpen: false, isCopy: false, name: this.props.config.groupId, description: '', projectId: '', runtime: this.props.config.runtime});
this.onGetProjects();
}
@@ -245,6 +248,99 @@ export class ProjectsPage extends React.Component<Props, State> {
});
}
+ getEmptyState() {
+ const {loading} = this.state;
+ return (
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ {loading && <Spinner className="progress-stepper" isSVG diameter="80px" aria-label="Loading..."/>}
+ {!loading &&
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={SearchIcon}/>
+ <Title headingLevel="h2" size="lg">
+ No results found
+ </Title>
+ </EmptyState>
+ }
+ </Bullseye>
+ </Td>
+ </Tr>
+ )
+ }
+
+ getProjectsTable() {
+ const {projects, filter} = this.state;
+ const projs = projects.filter(p => p.name.toLowerCase().includes(filter) || p.description.toLowerCase().includes(filter));
+ return (
+ <TableComposable aria-label="Projects" variant={"compact"}>
+ <Thead>
+ <Tr>
+ <Th key='type'>Runtime</Th>
+ <Th key='projectId'>Project ID</Th>
+ <Th key='name'>Name</Th>
+ <Th key='description'>Description</Th>
+ <Th key='commit'>Commit</Th>
+ <Th key='deployment'>Environment</Th>
+ <Th key='action'></Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {projs.map(project => (
+ <Tr key={project.projectId}>
+ <Td modifier={"fitContent"}>
+ <Tooltip content={project.runtime} position={"left"}>
+ <Badge className="runtime-badge">{project.runtime.substring(0, 1).toUpperCase()}</Badge>
+ </Tooltip>
+ </Td>
+ <Td>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={e => this.props.onSelect?.call(this, project)}>
+ {project.projectId}
+ </Button>
+ </Td>
+ <Td>{project.name}</Td>
+ <Td>{project.description}</Td>
+ <Td isActionCell>
+ <Tooltip content={project.lastCommit} position={"bottom"}>
+ <Badge>{project.lastCommit?.substr(0, 7)}</Badge>
+ </Tooltip>
+ </Td>
+ <Td noPadding style={{width: "180px"}}>
+ <Flex direction={{default: "row"}}>
+ {this.getDeploymentByEnvironments(project.projectId).map(value => (
+ <FlexItem className="badge-flex-item" key={value[0]}>
+ <Badge className="badge" isRead={!value[1]}>{value[0]}</Badge>
+ </FlexItem>
+ ))}
+ </Flex>
+ </Td>
+ <Td isActionCell>
+ <OverflowMenu breakpoint="md">
+ <OverflowMenuContent>
+ <OverflowMenuGroup groupType="button">
+ <OverflowMenuItem>
+ <Tooltip content={"Copy project"} position={"bottom"}>
+ <Button variant={"plain"} icon={<CopyIcon/>}
+ onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
+ </Tooltip>
+ </OverflowMenuItem>
+ <OverflowMenuItem>
+ <Tooltip content={"Delete project"} position={"bottom"}>
+ <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => this.onProjectDelete(project)}></Button>
+ </Tooltip>
+ </OverflowMenuItem>
+ </OverflowMenuGroup>
+ </OverflowMenuContent>
+ </OverflowMenu>
+ </Td>
+ </Tr>
+ ))}
+ {projs.length === 0 && this.getEmptyState()}
+ </Tbody>
+ </TableComposable>
+ )
+ }
+
render() {
const projects = this.state.projects.filter(p => p.name.toLowerCase().includes(this.state.filter) || p.description.toLowerCase().includes(this.state.filter));
return (
@@ -253,84 +349,7 @@ export class ProjectsPage extends React.Component<Props, State> {
<MainToolbar title={this.title()} tools={this.tools()}/>
</PageSection>
<PageSection isFilled className="kamelets-page">
- <TableComposable aria-label="Projects" variant={"compact"}>
- <Thead>
- <Tr>
- <Th key='type'>Runtime</Th>
- <Th key='projectId'>Project ID</Th>
- <Th key='name'>Name</Th>
- <Th key='description'>Description</Th>
- <Th key='commit'>Commit</Th>
- <Th key='deployment'>Environment</Th>
- <Th key='action'></Th>
- </Tr>
- </Thead>
- <Tbody>
- {projects.map(project => (
- <Tr key={project.projectId}>
- <Td modifier={"fitContent"}>
- <Tooltip content={project.runtime} position={"left"}>
- <Badge className="runtime-badge">{project.runtime.substring(0, 1).toUpperCase()}</Badge>
- </Tooltip>
- </Td>
- <Td>
- <Button style={{padding: '6px'}} variant={"link"} onClick={e => this.props.onSelect?.call(this, project)}>
- {project.projectId}
- </Button>
- </Td>
- <Td>{project.name}</Td>
- <Td>{project.description}</Td>
- <Td isActionCell>
- <Tooltip content={project.lastCommit} position={"bottom"}>
- <Badge>{project.lastCommit?.substr(0, 7)}</Badge>
- </Tooltip>
- </Td>
- <Td noPadding style={{width: "180px"}}>
- <Flex direction={{default: "row"}}>
- {this.getDeploymentByEnvironments(project.projectId).map(value => (
- <FlexItem className="badge-flex-item" key={value[0]}>
- <Badge className="badge" isRead={!value[1]}>{value[0]}</Badge>
- </FlexItem>
- ))}
- </Flex>
- </Td>
- <Td isActionCell>
- <OverflowMenu breakpoint="md">
- <OverflowMenuContent>
- <OverflowMenuGroup groupType="button">
- <OverflowMenuItem>
- <Tooltip content={"Copy project"} position={"bottom"}>
- <Button variant={"plain"} icon={<CopyIcon/>}
- onClick={e => this.setState({isCreateModalOpen: true, isCopy: true, projectToCopy: project})}></Button>
- </Tooltip>
- </OverflowMenuItem>
- <OverflowMenuItem>
- <Tooltip content={"Delete project"} position={"bottom"}>
- <Button variant={"plain"} icon={<DeleteIcon/>} onClick={e => this.onProjectDelete(project)}></Button>
- </Tooltip>
- </OverflowMenuItem>
- </OverflowMenuGroup>
- </OverflowMenuContent>
- </OverflowMenu>
- </Td>
- </Tr>
- ))}
- {projects.length === 0 &&
- <Tr>
- <Td colSpan={8}>
- <Bullseye>
- <EmptyState variant={EmptyStateVariant.small}>
- <EmptyStateIcon icon={SearchIcon}/>
- <Title headingLevel="h2" size="lg">
- No results found
- </Title>
- </EmptyState>
- </Bullseye>
- </Td>
- </Tr>
- }
- </Tbody>
- </TableComposable>
+ {this.getProjectsTable()}
</PageSection>
{this.createModalForm()}
{this.deleteModalForm()}
diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css
index 38e2973..77ff41e 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -1274,6 +1274,7 @@
overflow: auto;
flex-shrink: unset;
flex-grow: 1;
+ background-color: var(--pf-global--BackgroundColor--light-300);
}
.karavan .designer-page {
[camel-karavan] 07/12: Kamalets in projects
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit dc1356fcf1881de4c4ebaedd39b946026bfc9b1f
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 18 17:55:42 2022 -0500
Kamalets in projects
---
.../apache/camel/karavan/api/KameletResources.java | 10 ++++++----
.../org/apache/camel/karavan/model/Kamelet.java | 6 ------
.../apache/camel/karavan/service/ImportService.java | 21 ++++++++++++++-------
.../camel/karavan/service/InfinispanService.java | 19 -------------------
karavan-designer/src/designer/karavan.css | 5 +++++
5 files changed, 25 insertions(+), 36 deletions(-)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java
index 30bcea3..d06f15d 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.karavan.api;
+import org.apache.camel.karavan.model.Project;
+import org.apache.camel.karavan.model.ProjectFile;
import org.apache.camel.karavan.service.CodeService;
import org.apache.camel.karavan.service.InfinispanService;
@@ -40,11 +42,11 @@ public class KameletResources {
@Produces(MediaType.TEXT_PLAIN)
public String getCustomYamls() {
StringBuilder kamelets = new StringBuilder(codeService.getResourceFile("/kamelets/kamelets.yaml"));
- List<String> customKameletNames = infinispanService.getKameletNames();
- if (customKameletNames.size() > 0) {
+ List<ProjectFile> custom = infinispanService.getProjectFiles(Project.NAME_KAMELETS);
+ if (custom.size() > 0) {
kamelets.append("\n---\n");
- kamelets.append(infinispanService.getKameletNames().stream()
- .map(name -> infinispanService.getKameletYaml(name))
+ kamelets.append(custom.stream()
+ .map(file -> file.getCode())
.collect(Collectors.joining("\n---\n")));
}
return kamelets.toString();
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/Kamelet.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/Kamelet.java
deleted file mode 100644
index 7974390..0000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/Kamelet.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.apache.camel.karavan.model;
-
-public abstract class Kamelet {
- public static final String CACHE = "kamelets";
-
-}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
index 12d153a..05cbe5d 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
@@ -83,7 +83,7 @@ public class ImportService {
try {
Project templates = infinispanService.getProject(Project.NAME_TEMPLATES);
if (templates == null) {
- templates = new Project("templates", "Templates", "Templates", "quarkus", "");
+ templates = new Project(Project.NAME_TEMPLATES, "Templates", "Templates", "quarkus", "");
infinispanService.saveProject(templates, true);
codeService.getApplicationPropertiesTemplates().forEach((name, value) -> {
@@ -100,12 +100,19 @@ public class ImportService {
void loadCustomKamelets(String data) {
LOGGER.info("Load custom Kamelets from Git");
try {
- List<Tuple2<String, String>> repo = gitService.readKameletsFromRepository();
- repo.forEach(p -> {
- String name = p.getItem1();
- String yaml = p.getItem2();
- infinispanService.saveKamelet(name, yaml);
- });
+ Project kamelets = infinispanService.getProject(Project.NAME_KAMELETS);
+ if (kamelets == null) {
+ kamelets = new Project(Project.NAME_KAMELETS, "Custom Kamelets", "Custom Kamelets", "quarkus", "");
+ infinispanService.saveProject(kamelets, true);
+
+ List<Tuple2<String, String>> repo = gitService.readKameletsFromRepository();
+ repo.forEach(p -> {
+ String name = p.getItem1();
+ String yaml = p.getItem2();
+ ProjectFile file = new ProjectFile(name, yaml, Project.NAME_KAMELETS);
+ infinispanService.saveProjectFile(file);
+ });
+ }
} catch (Exception e) {
LOGGER.error("Error during project import", e);
}
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 b8f44b1..b7ae729 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
@@ -20,13 +20,11 @@ import org.apache.camel.karavan.model.CamelStatus;
import org.apache.camel.karavan.model.DeploymentStatus;
import org.apache.camel.karavan.model.Environment;
import org.apache.camel.karavan.model.GroupedKey;
-import org.apache.camel.karavan.model.Kamelet;
import org.apache.camel.karavan.model.PipelineStatus;
import org.apache.camel.karavan.model.PodStatus;
import org.apache.camel.karavan.model.Project;
import org.apache.camel.karavan.model.ProjectFile;
import org.apache.camel.karavan.model.ServiceStatus;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.Search;
@@ -37,7 +35,6 @@ import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.cache.SingleFileStoreConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
-import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.query.dsl.QueryFactory;
import org.jboss.logging.Logger;
@@ -58,7 +55,6 @@ public class InfinispanService {
BasicCache<GroupedKey, PodStatus> podStatuses;
BasicCache<GroupedKey, CamelStatus> camelStatuses;
BasicCache<GroupedKey, ServiceStatus> serviceStatuses;
- BasicCache<String, String> kamelets;
BasicCache<String, Environment> environments;
@Inject
@@ -96,7 +92,6 @@ public class InfinispanService {
podStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PodStatus.CACHE, builder.build());
serviceStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(ServiceStatus.CACHE, builder.build());
camelStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(CamelStatus.CACHE, builder.build());
- kamelets = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Kamelet.CACHE, builder.build());
cleanData();
} else {
@@ -109,9 +104,7 @@ public class InfinispanService {
podStatuses = cacheManager.administration().getOrCreateCache(PodStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, PodStatus.CACHE)));
serviceStatuses = cacheManager.administration().getOrCreateCache(ServiceStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, ServiceStatus.CACHE)));
camelStatuses = cacheManager.administration().getOrCreateCache(CamelStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, CamelStatus.CACHE)));
- kamelets = cacheManager.administration().getOrCreateCache(Kamelet.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Kamelet.CACHE)));
}
-// org.hibernate.search.engine.search.loading.spi.EntityLoader
}
private void cleanData() {
@@ -283,18 +276,6 @@ public class InfinispanService {
camelStatuses.remove(GroupedKey.create(name, env));
}
- public List<String> getKameletNames() {
- return kamelets.keySet().stream().collect(Collectors.toList());
- }
-
- public String getKameletYaml(String name) {
- return kamelets.get(name);
- }
-
- public void saveKamelet(String name, String yaml) {
- kamelets.put(name, yaml);
- }
-
public List<Environment> getEnvironments() {
return environments.values().stream().collect(Collectors.toList());
}
diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css
index 77ff41e..ae823fb 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -128,6 +128,11 @@
padding-right: 6px;
}
+.kamelets-page .kamelet-card .pf-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
+}
+
.kamelets-page .kamelet-card .pf-c-card__body {
overflow: hidden;
position: relative;