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/11 14:05:47 UTC
[camel-karavan] 04/04: Templates page
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 d9296297387251bd6387ebcb7bb1aeb04972b33f
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Fri Nov 11 09:05:28 2022 -0500
Templates page
---
.../apache/camel/karavan/api/ProjectResource.java | 3 +-
.../apache/camel/karavan/api/TemplateResource.java | 60 ++++----------------
karavan-app/src/main/webapp/src/Main.tsx | 14 +++--
karavan-app/src/main/webapp/src/api/KaravanApi.tsx | 22 ++++++++
.../main/webapp/src/config/ConfigurationPage.tsx | 66 +++++++++++++++++-----
.../main/webapp/src/dashboard/DashboardPage.tsx | 2 +-
.../src/main/webapp/src/projects/ProjectInfo.tsx | 1 -
.../src/main/webapp/src/projects/ProjectPage.tsx | 66 ++++++++++++++++------
.../src/main/webapp/src/projects/ProjectsPage.tsx | 2 +-
9 files changed, 149 insertions(+), 87 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 85a981f..b2e12b6 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,6 +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))
.sorted(Comparator.comparing(Project::getProjectId))
.collect(Collectors.toList());
}
@@ -86,7 +88,6 @@ public class ProjectResource {
Project s = infinispanService.getProject(sourceProject);
project.setRuntime(s.getRuntime());
infinispanService.saveProject(project, false);
-
// Copy files
Map<GroupedKey, ProjectFile> map = infinispanService.getProjectFiles(sourceProject).stream()
.collect(Collectors.toMap(f -> new GroupedKey(project.getProjectId(), f.getName()), f -> f));
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
index b2e12b6..2be7c7e 100644
--- 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
@@ -16,82 +16,46 @@
*/
package org.apache.camel.karavan.api;
-import org.apache.camel.karavan.model.GroupedKey;
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.DELETE;
import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
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.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.util.Comparator;
import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-@Path("/api/project")
-public class ProjectResource {
+@Path("/api/template")
+public class TemplateResource {
@Inject
InfinispanService infinispanService;
@GET
@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))
- .sorted(Comparator.comparing(Project::getProjectId))
- .collect(Collectors.toList());
+ public Project get() throws Exception {
+ return infinispanService.getProject(Project.NAME_TEMPLATES);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
- @Path("/{project}")
- public Project get(@PathParam("project") String project) throws Exception {
- return infinispanService.getProject(project);
+ @Path("/files")
+ public List<ProjectFile> getFiles() throws Exception {
+ return infinispanService.getProjectFiles(Project.NAME_TEMPLATES);
}
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
- public Project save(Project project) throws Exception {
- infinispanService.saveProject(project, false);
- return project;
- }
-
- @DELETE
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/{project}")
- public void delete(@HeaderParam("username") String username,
- @PathParam("project") String project) throws Exception {
- String projectId = URLDecoder.decode(project, StandardCharsets.UTF_8.toString());
- infinispanService.getProjectFiles(projectId).forEach(file -> infinispanService.deleteProjectFile(projectId, file.getName()));
- infinispanService.deleteProject(projectId);
- }
-
- @POST
- @Produces(MediaType.APPLICATION_JSON)
- @Consumes(MediaType.APPLICATION_JSON)
- @Path("/copy/{sourceProject}")
- public Project copy(@PathParam("sourceProject") String sourceProject, Project project) throws Exception {
-// Save project
- Project s = infinispanService.getProject(sourceProject);
- project.setRuntime(s.getRuntime());
- infinispanService.saveProject(project, false);
-// Copy files
- Map<GroupedKey, ProjectFile> map = infinispanService.getProjectFiles(sourceProject).stream()
- .collect(Collectors.toMap(f -> new GroupedKey(project.getProjectId(), f.getName()), f -> f));
- infinispanService.saveProjectFiles(map);
- return project;
+ 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/webapp/src/Main.tsx b/karavan-app/src/main/webapp/src/Main.tsx
index ccb825e..f3dcdc3 100644
--- a/karavan-app/src/main/webapp/src/Main.tsx
+++ b/karavan-app/src/main/webapp/src/Main.tsx
@@ -13,7 +13,6 @@ import {KaravanApi} from "./api/KaravanApi";
import {SsoApi} from "./api/SsoApi";
import {KameletApi} from "karavan-core/lib/api/KameletApi";
import './designer/karavan.css';
-import {ConfigurationPage} from "./config/ConfigurationPage";
import {KameletsPage} from "./kamelets/KameletsPage";
import {v4 as uuidv4} from "uuid";
import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
@@ -29,7 +28,7 @@ import KameletsIcon from "@patternfly/react-icons/dist/js/icons/registry-icon";
import DashboardIcon from "@patternfly/react-icons/dist/js/icons/tachometer-alt-icon";
import EipIcon from "@patternfly/react-icons/dist/js/icons/topology-icon";
import ComponentsIcon from "@patternfly/react-icons/dist/js/icons/module-icon";
-import ConfigurationIcon from "@patternfly/react-icons/dist/js/icons/cogs-icon";
+import TemplatesIcon from "@patternfly/react-icons/dist/js/icons/cogs-icon";
import {MainLogin} from "./MainLogin";
import {DashboardPage} from "./dashboard/DashboardPage";
@@ -67,6 +66,7 @@ interface State {
pageId: string,
projects: Project[],
project?: Project,
+ templates?: Project,
isModalOpen: boolean,
projectToDelete?: Project,
openapi: string,
@@ -125,6 +125,9 @@ 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();
@@ -162,7 +165,7 @@ export class Main extends React.Component<Props, State> {
new MenuItem("eip", "Enterprise Integration Patterns", <EipIcon/>),
new MenuItem("kamelets", "Kamelets", <KameletsIcon/>),
new MenuItem("components", "Components", <ComponentsIcon/>),
- new MenuItem("configuration", "Configuration", <ConfigurationIcon/>)
+ new MenuItem("templates", "Templates", <TemplatesIcon/>)
]
return (<Flex className="nav-buttons" direction={{default: "column"}} style={{height: "100%"}}
spaceItems={{default: "spaceItemsNone"}}>
@@ -235,12 +238,13 @@ export class Main extends React.Component<Props, State> {
toast={this.toast}
config={this.state.config}/>}
{this.state.pageId === 'project' && this.state.project &&
- <ProjectPage project={this.state.project} config={this.state.config}/>}
+ <ProjectPage key="projects" project={this.state.project} config={this.state.config}/>}
{this.state.pageId === 'dashboard' && <DashboardPage key={this.state.request}
onSelect={this.onProjectSelect}
toast={this.toast}
config={this.state.config}/>}
- {this.state.pageId === 'configuration' && <ConfigurationPage/>}
+ {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/webapp/src/api/KaravanApi.tsx b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
index 46151c2..e6e2003 100644
--- a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
@@ -277,6 +277,28 @@ 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 => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ console.log(err);
+ });
+ }
+
static async pipelineRun(project: Project, environment: string, after: (res: AxiosResponse<any>) => void) {
instance.post('/api/kubernetes/pipeline/' + environment, project)
.then(res => {
diff --git a/karavan-app/src/main/webapp/src/config/ConfigurationPage.tsx b/karavan-app/src/main/webapp/src/config/ConfigurationPage.tsx
index 1a88233..c9efa9f 100644
--- a/karavan-app/src/main/webapp/src/config/ConfigurationPage.tsx
+++ b/karavan-app/src/main/webapp/src/config/ConfigurationPage.tsx
@@ -1,39 +1,77 @@
import React from 'react';
import {
- Gallery,
- PageSection
+ Badge, Bullseye, Button, EmptyState, EmptyStateIcon, EmptyStateVariant, Flex, FlexItem,
+ Gallery, OverflowMenu, OverflowMenuContent, OverflowMenuGroup, OverflowMenuItem,
+ PageSection, Tab, Tabs, TabTitleText, Text, TextContent, TextInput, Title, Toolbar, ToolbarContent, ToolbarItem, Tooltip
} from '@patternfly/react-core';
import '../designer/karavan.css';
+import {MainToolbar} from "../MainToolbar";
+import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import CopyIcon from "@patternfly/react-icons/dist/esm/icons/copy-icon";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
+import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {KaravanApi} from "../api/KaravanApi";
+import {DeploymentStatus, Project} from "../projects/ProjectModels";
interface Props {
}
interface State {
- repository: string,
- path: string,
- integrations: []
+ templates: [],
}
export class ConfigurationPage extends React.Component<Props, State> {
public state: State = {
- repository: '',
- path: '',
- integrations: []
+ templates: []
};
componentDidMount() {
+ this.onGetTemplates();
+ }
+ onGetTemplates = () => {
+ // KaravanApi.getTemplates((templates: []) => {
+ // console.log(templates)
+ // this.setState({templates: templates})
+ // });
}
+ tools = () => (<Toolbar id="toolbar-group-types">
+ <ToolbarContent>
+ <ToolbarItem>
+ <Button variant="link" icon={<RefreshIcon/>} onClick={e => this.onGetTemplates()}/>
+ </ToolbarItem>
+ </ToolbarContent>
+ </Toolbar>);
+
+ title = () => (<TextContent>
+ <Text component="h2">Configuration</Text>
+ </TextContent>);
+
render() {
return (
- <PageSection padding={{ default: 'noPadding' }}>
- <Gallery hasGutter>
- {/*{this.state.integrations.map(value => (*/}
- {/* // <IntegrationCard name={value}/>*/}
- {/*))}*/}
- </Gallery>
+ <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">
+ <Tabs
+ // activeKey={activeTabKey}
+ // onSelect={handleTabClick}
+ aria-label="Configurations"
+ role="tabs"
+ >
+ <Tab eventKey={0} title={<TabTitleText>Templates</TabTitleText>} aria-label="Templates">
+ Templates
+ </Tab>
+ <Tab eventKey={11} title={<TabTitleText>Environments</TabTitleText>}>
+ Environments
+ </Tab>
+ </Tabs>
+ </PageSection>
</PageSection>
);
}
diff --git a/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx b/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx
index fbff4d5..8f5fe20 100644
--- a/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx
+++ b/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx
@@ -135,7 +135,7 @@ export class DashboardPage extends React.Component<Props, State> {
</Toolbar>);
title = () => (<TextContent>
- <Text component="h1">Dashboard</Text>
+ <Text component="h2">Dashboard</Text>
</TextContent>);
getEnvironments(): string [] {
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
index 10fd3df..f8525e5 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
@@ -330,7 +330,6 @@ export class ProjectInfo extends React.Component<Props, State> {
}
getPipelineState(env: string) {
- // console.log(this.state.pipelineStatus)
const status = this.state.pipelineStatus;
const pipeline = status?.pipelineName;
const pipelineResult = status?.result;
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx b/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
index f53057c..9150d7b 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
@@ -21,7 +21,7 @@ import {
ToggleGroup,
ToggleGroupItem,
CodeBlockCode,
- CodeBlock, Skeleton, Checkbox, Tabs, Tab, Tooltip
+ CodeBlock, Skeleton, Checkbox, Tabs, Tab, Tooltip, ToolbarItem
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {MainToolbar} from "../MainToolbar";
@@ -47,9 +47,12 @@ import {UploadModal} from "./UploadModal";
import {ProjectInfo} from "./ProjectInfo";
import {ProjectOperations} from "./ProjectOperations";
import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
+import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon";
+import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
interface Props {
project: Project,
+ isTemplates?: boolean,
config: any,
}
@@ -165,6 +168,7 @@ export class ProjectPage extends React.Component<Props, State> {
}
tools = () => {
+ const {isTemplates, project} = this.props;
const {file, mode} = this.state;
const isFile = file !== undefined;
const isYaml = file !== undefined && file.name.endsWith("yaml");
@@ -172,6 +176,30 @@ export class ProjectPage extends React.Component<Props, State> {
const isProperties = file !== undefined && file.name.endsWith("properties");
return <Toolbar id="toolbar-group-types">
<ToolbarContent>
+ {isTemplates &&
+ <ToolbarItem>
+ <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
+ <FlexItem>
+ <Tooltip content={project?.lastCommit} position={"right"}>
+ <Badge>{project?.lastCommit ? project?.lastCommit?.substr(0, 7) : "-"}</Badge>
+ </Tooltip>
+ </FlexItem>
+ <FlexItem>
+ <Button variant="primary" icon={<PushIcon/>} onClick={e => {
+ KaravanApi.push(this.props.project, res => {
+ console.log(res)
+ if (res.status === 200 || res.status === 201) {
+ this.onRefresh();
+ } else {
+ // Todo notification
+ }
+ });
+ }}>Commit</Button>
+ </FlexItem>
+ </Flex>
+ </ToolbarItem>
+ }
+ {!isTemplates &&
<Flex className="toolbar" direction={{default: "row"}} alignItems={{default:"alignItemsCenter"}}>
{isYaml && <FlexItem>
<ToggleGroup>
@@ -210,7 +238,7 @@ export class ProjectPage extends React.Component<Props, State> {
<Button variant="secondary" icon={<UploadIcon/>}
onClick={e => this.setState({isUploadModalOpen: true})}>Upload</Button>
</FlexItem>}
- </Flex>
+ </Flex>}
</ToolbarContent>
</Toolbar>
}
@@ -233,6 +261,7 @@ export class ProjectPage extends React.Component<Props, State> {
}
title = () => {
+ const {project, isTemplates} = this.props;
const file = this.state.file;
const isFile = file !== undefined;
const isLog = file !== undefined && file.name.endsWith("log");
@@ -242,7 +271,7 @@ export class ProjectPage extends React.Component<Props, State> {
<div>
<Breadcrumb>
<BreadcrumbItem to="#" onClick={event => this.setState({file: undefined})}>
- {"Project: " + this.props.project?.projectId}
+ {"Project: " + project?.projectId}
</BreadcrumbItem>
<BreadcrumbItem to="#" isActive>{this.getType(file)}</BreadcrumbItem>
</Breadcrumb>
@@ -252,7 +281,7 @@ export class ProjectPage extends React.Component<Props, State> {
</div>
}
{!isFile && <TextContent className="title">
- <Text component="h1">Project</Text>
+ <Text component="h2">{isTemplates ? 'Templates' : 'Project: ' + project?.projectId}</Text>
</TextContent>}
</div>)
};
@@ -445,6 +474,7 @@ export class ProjectPage extends React.Component<Props, State> {
}
render() {
+ const {isTemplates} = this.props;
const {file, mode, tab} = this.state;
const isYaml = file !== undefined && file.name.endsWith("yaml");
const isIntegration = isYaml && file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code);
@@ -462,18 +492,22 @@ export class ProjectPage extends React.Component<Props, State> {
<PageSection isFilled className="kamelets-page project-page-section"
padding={{default: file !== undefined ? 'noPadding' : 'noPadding'}}>
<Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
- <FlexItem>
- <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 === 'operations' && <ProjectOperations environments={this.state.environments} project={this.props.project} config={this.props.config}/>}
- </PageSection>
- </FlexItem>
+ {!isTemplates &&
+ <FlexItem>
+ <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 === 'operations' && <ProjectOperations environments={this.state.environments} project={this.props.project} config={this.props.config}/>}
+ </PageSection>
+ </FlexItem>
+ }
</Flex>
{tab === 'development' && this.getProjectFiles()}
</PageSection>}
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
index 15676f6..08bb7c7 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
@@ -140,7 +140,7 @@ export class ProjectsPage extends React.Component<Props, State> {
</Toolbar>);
title = () => (<TextContent>
- <Text component="h1">Projects</Text>
+ <Text component="h2">Projects</Text>
</TextContent>);
closeModal = () => {