You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/07/01 17:22:35 UTC
[camel-karavan] 02/06: Refactor for #809
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 6c64bd46db012daddae7c910d2a985728256bdbb
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Mon Jun 26 10:08:49 2023 -0400
Refactor for #809
---
karavan-app/src/main/webui/src/Main.tsx | 7 +-
karavan-app/src/main/webui/src/api/KaravanApi.tsx | 3 +-
.../src/main/webui/src/api/ProjectModels.ts | 8 +
karavan-app/src/main/webui/src/api/ProjectStore.ts | 24 ++-
karavan-app/src/main/webui/src/index.css | 5 +-
.../src/main/webui/src/project/ProjectPage.tsx | 214 ++++-----------------
.../src/main/webui/src/project/ProjectPanel.tsx | 49 +++++
.../src/main/webui/src/project/ProjectTitle.tsx | 61 ++++++
.../src/main/webui/src/project/ProjectToolbar.tsx | 42 ++--
.../src/main/webui/src/project/RunnerToolbar.tsx | 5 +-
.../webui/src/project/dashboard/DashboardTab.tsx | 20 +-
.../src/project/dashboard/RunnerInfoContext.tsx | 3 +-
.../src/project/dashboard/RunnerInfoMemory.tsx | 1 -
.../src/main/webui/src/project/files/FilesTab.tsx | 30 +--
.../main/webui/src/project/files/FilesToolbar.tsx | 24 +++
.../src/project/pipeline/ProjectPipelineTab.tsx | 42 ++--
.../src/main/webui/src/project/trace/TraceTab.tsx | 12 +-
.../main/webui/src/projects/CreateProjectModal.tsx | 10 +-
.../src/main/webui/src/projects/ProjectsPage.tsx | 7 +-
.../main/webui/src/projects/ProjectsTableRow.tsx | 8 +-
20 files changed, 281 insertions(+), 294 deletions(-)
diff --git a/karavan-app/src/main/webui/src/Main.tsx b/karavan-app/src/main/webui/src/Main.tsx
index 6b64d6e1..39f3192f 100644
--- a/karavan-app/src/main/webui/src/Main.tsx
+++ b/karavan-app/src/main/webui/src/Main.tsx
@@ -32,6 +32,7 @@ import {Subscription} from "rxjs";
import {ProjectEventBus} from "./api/ProjectEventBus";
import {Project} from "./api/ProjectModels";
import {ProjectPage} from "./project/ProjectPage";
+import {useAppConfigStore} from "./api/ProjectStore";
class ToastMessage {
id: string = ''
@@ -129,6 +130,7 @@ export class Main extends React.Component<Props, State> {
getData() {
KaravanApi.getConfiguration((config: any) => {
this.setState({config: config, request: uuidv4()});
+ useAppConfigStore.setState({config: config})
});
this.updateKamelets();
this.updateComponents();
@@ -242,10 +244,9 @@ export class Main extends React.Component<Props, State> {
<FlexItem flex={{default: "flex_2"}} style={{height: "100%"}}>
{this.state.pageId === 'projects' &&
<ProjectsPage key={this.state.request}
- toast={this.toast}
- config={this.state.config}/>}
+ toast={this.toast}/>}
{this.state.pageId === 'project' &&
- <ProjectPage key="projects" config={this.state.config}/>}
+ <ProjectPage key="projects"/>}
{this.state.pageId === 'dashboard' && <DashboardPage key={this.state.request}
toast={this.toast}
config={this.state.config}/>}
diff --git a/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 06811cb6..617b2e96 100644
--- a/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -1,5 +1,6 @@
import axios, {AxiosResponse } from "axios";
import {
+ AppConfig,
CamelStatus,
DeploymentStatus,
PipelineStatus,
@@ -130,7 +131,7 @@ export class KaravanApi {
});
}
- static async getConfiguration(after: (config: {}) => void) {
+ static async getConfiguration(after: (config: AppConfig) => void) {
instance.get('/api/configuration')
.then(res => {
if (res.status === 200) {
diff --git a/karavan-app/src/main/webui/src/api/ProjectModels.ts b/karavan-app/src/main/webui/src/api/ProjectModels.ts
index b65ea9a8..63757dcc 100644
--- a/karavan-app/src/main/webui/src/api/ProjectModels.ts
+++ b/karavan-app/src/main/webui/src/api/ProjectModels.ts
@@ -1,3 +1,11 @@
+export class AppConfig {
+ version: string = '';
+ environment: string = '';
+ environments: string[] = [];
+ runtime: string = '';
+ runtimes: string[] = [];
+}
+
export class Project {
projectId: string = '';
name: string = '';
diff --git a/karavan-app/src/main/webui/src/api/ProjectStore.ts b/karavan-app/src/main/webui/src/api/ProjectStore.ts
index ca385656..a524f6bc 100644
--- a/karavan-app/src/main/webui/src/api/ProjectStore.ts
+++ b/karavan-app/src/main/webui/src/api/ProjectStore.ts
@@ -16,12 +16,20 @@
*/
import {create} from 'zustand'
-import {DeploymentStatus, Project, ProjectFile} from "./ProjectModels";
+import {AppConfig, DeploymentStatus, Project, ProjectFile} from "./ProjectModels";
+
+interface AppConfigState {
+ config: AppConfig;
+ setConfig: (config: AppConfig) => void;
+}
+
+export const useAppConfigStore = create<AppConfigState>((set) => ({
+ config: new AppConfig(),
+ setConfig: (config: AppConfig) => {
+ set({config: config})
+ },
+}))
-const projects: Project[] = [];
-var project: Project = new Project();
-const files: ProjectFile[] = [];
-var file: ProjectFile | undefined = undefined;
interface ProjectsState {
projects: Project[];
@@ -70,14 +78,14 @@ export const useFilesStore = create<FilesState>((set) => ({
interface FileState {
file?: ProjectFile;
- operation: "create" | "select" | "delete" | "none" | "copy";
- setFile: (file: ProjectFile, operation: "create" | "select" | "delete"| "none" | "copy") => void;
+ operation: "create" | "select" | "delete" | "none" | "copy" | "upload";
+ setFile: (file: ProjectFile, operation: "create" | "select" | "delete"| "none" | "copy" | "upload") => void;
}
export const useFileStore = create<FileState>((set) => ({
file: undefined,
operation: "none",
- setFile: (file: ProjectFile, operation: "create" | "select" | "delete"| "none" | "copy") => {
+ setFile: (file: ProjectFile, operation: "create" | "select" | "delete"| "none" | "copy" | "upload") => {
set((state: FileState) => ({
file: file,
operation: operation,
diff --git a/karavan-app/src/main/webui/src/index.css b/karavan-app/src/main/webui/src/index.css
index e3525ba9..1baa8f91 100644
--- a/karavan-app/src/main/webui/src/index.css
+++ b/karavan-app/src/main/webui/src/index.css
@@ -172,9 +172,8 @@
margin-bottom: 16px;
}
-.karavan .project-page .project-bottom {
- overflow: auto;
- max-height: 100vh;
+.karavan .project-page .project-tab-panel .pf-c-panel__header {
+ padding-bottom: 0;
}
.karavan .project-page .project-operations {
diff --git a/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index 34c6c429..edf0ef6c 100644
--- a/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -1,19 +1,11 @@
import React, {useEffect, useState} from 'react';
import {
- Badge,
- Breadcrumb,
- BreadcrumbItem,
PageSection,
- Text,
- TextContent,
- Flex,
- FlexItem,
CodeBlockCode,
- CodeBlock, Skeleton, Tabs, Tab
+ CodeBlock, Skeleton
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {KaravanApi} from "../api/KaravanApi";
-import {KaravanDesigner} from "../designer/KaravanDesigner";
import FileSaver from "file-saver";
import Editor from "@monaco-editor/react";
import {PropertiesEditor} from "./PropertiesEditor";
@@ -21,84 +13,56 @@ import {ProjectModel, ProjectProperty} from "karavan-core/lib/model/ProjectModel
import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
import {ProjectToolbar} from "./ProjectToolbar";
-import {FilesTab} from "./files/FilesTab";
import {EventBus} from "../designer/utils/EventBus";
import {ProjectLog} from "./ProjectLog";
-import {getProjectFileType, ProjectFile, ProjectFileTypes} from "../api/ProjectModels";
-import {useProjectStore} from "../api/ProjectStore";
+import {AppConfig, ProjectFile, ProjectFileTypes} from "../api/ProjectModels";
+import {useAppConfigStore, useFileStore, useProjectStore} from "../api/ProjectStore";
import {ProjectService} from "../api/ProjectService";
-import {DashboardTab} from "./dashboard/DashboardTab";
-import {TraceTab} from "./trace/TraceTab";
-import {ProjectPipelineTab} from "./pipeline/ProjectPipelineTab";
import {MainToolbar} from "../common/MainToolbar";
import {CreateFileModal} from "./CreateFileModal";
import {DeleteFileModal} from "./DeleteFileModal";
+import {ProjectTitle} from "./ProjectTitle";
+import {ProjectPanel} from "./ProjectPanel";
-interface Props {
- config: any,
-}
-
-export const ProjectPage = (props: Props) => {
+export const ProjectPage = () => {
const [isUploadModalOpen, setIsUploadModalOpen] = useState<boolean>(false);
- const [isDeleteModalOpen, setIsDeleteModalOpen] = useState<boolean>(false);
const [editAdvancedProperties, setEditAdvancedProperties] = useState<boolean>(false);
- const [files, setFiles] = useState<ProjectFile[]>([]);
- const [file, setFile] = useState<ProjectFile | undefined>(undefined);
- const [fileToDelete, setFileToDelete] = useState<ProjectFile | undefined>(undefined);
+ const {file, operation} = useFileStore();
const [mode, setMode] = useState<"design" | "code">("design");
const [key, setKey] = useState<string>('');
const [tab, setTab] = useState<string | number>('files');
- const [environments, setEnvironments] = useState<string[]>((
- props.config.environments && Array.isArray(props.config.environments)) ? Array.from(props.config.environments) : []
- );
- const [environment, setEnvironment] = useState<string>(props.config.environment);
- const {project, setProject} = useProjectStore();
+ const {project} = useProjectStore();
+ const {config} = useAppConfigStore();
useEffect(() => {
- // console.log("UseEffect ProjectPage")
-
onRefresh();
- // const sub1 = ProjectEventBus.onCurrentRunner()?.subscribe((result) => {
- // setCurrentRunner(result || '');
- // });
- // return () => {
- // sub1.unsubscribe();
- // };
});
- function needCommit(): boolean {
- return project ? files.filter(f => f.lastUpdate > project.lastCommitTimestamp).length > 0 : false;
- }
-
function onRefresh () {
- ProjectService.refreshProjectData(environment);
+ ProjectService.refreshProjectData(config.environment);
}
function post (file: ProjectFile) {
KaravanApi.postProjectFile(file, res => {
if (res.status === 200) {
const newFile = res.data;
- setFiles((files => {
- const index = files.findIndex(f => f.name === newFile.name);
- if (index !== -1) files.splice(index, 1, newFile)
- else files.push(newFile);
- return files
- }))
+ // setFiles((files => {
+ // const index = files.findIndex(f => f.name === newFile.name);
+ // if (index !== -1) files.splice(index, 1, newFile)
+ // else files.push(newFile);
+ // return files
+ // }))
} else {
// console.log(res) //TODO show notification
}
})
}
- function copyToClipboard (data: string) {
- navigator.clipboard.writeText(data);
- }
-
function save (name: string, code: string) {
if (file) {
file.code = code;
- setFile(file);
+ // setFile(file);
post(file);
}
}
@@ -132,93 +96,33 @@ export const ProjectPage = (props: Props) => {
mode={mode}
isTemplates={false}
isKamelets={false}
- config={props.config}
addProperty={() => addProperty()}
- download={() => download()}
downloadImage={() => downloadImage()}
editAdvancedProperties={editAdvancedProperties}
setEditAdvancedProperties={checked => setEditAdvancedProperties(checked)}
setMode={mode => setMode(mode)}
setUploadModalOpen={() => setIsUploadModalOpen(isUploadModalOpen)}
- needCommit={needCommit()}
+ needCommit={false}
onRefresh={onRefresh}
/>
}
-
- function title () {
- const isFile = file !== undefined;
- const isLog = file !== undefined && file.name.endsWith("log");
- const filename = file ? file.name.substring(0, file.name.lastIndexOf('.')) : "";
- return (<div className="dsl-title project-title">
- {isFile && <Flex direction={{default: "column"}} >
- <FlexItem>
- <Breadcrumb>
- <BreadcrumbItem to="#" onClick={event => {
- setFile(undefined)
- onRefresh();
- }}>
- <div className={"project-breadcrumb"}>{project?.name + " (" + project?.projectId + ")"}</div>
- </BreadcrumbItem>
- </Breadcrumb>
- </FlexItem>
- <FlexItem>
- <Flex direction={{default: "row"}}>
- <FlexItem>
- <Badge>{getProjectFileType(file)}</Badge>
- </FlexItem>
- <FlexItem>
- <TextContent className="description">
- <Text>{isLog ? filename : file.name}</Text>
- </TextContent>
- </FlexItem>
- </Flex>
- </FlexItem>
- </Flex>}
- {!isFile && <Flex direction={{default: "column"}} >
- <FlexItem>
- <TextContent className="title">
- <Text component="h2">{project?.name + " (" + project?.projectId + ")"}</Text>
- </TextContent>
- </FlexItem>
- <FlexItem>
- <TextContent className="description">
- <Text>{project?.description}</Text>
- </TextContent>
- </FlexItem>
- </Flex>}
- </div>)
- };
-
- function closeModal (isPushing: boolean = false) {
- setIsUploadModalOpen(false);
- }
-
- function select (file: ProjectFile) {
- setFile(file);
- }
-
- function openDeleteConfirmation (file: ProjectFile) {
- setIsDeleteModalOpen(true)
- setFileToDelete(file);
- }
-
- function getDesigner () {
- return (
- file !== undefined &&
- <KaravanDesigner
- dark={false}
- key={"key"}
- filename={file.name}
- yaml={file.code}
- onSave={(name, yaml) => save(name, yaml)}
- onSaveCustomCode={(name, code) => post(new ProjectFile(name + ".java", project.projectId, code, Date.now()))}
- onGetCustomCode={(name, javaType) => {
- return new Promise<string | undefined>(resolve => resolve(files.filter(f => f.name === name + ".java")?.at(0)?.code))
- }}
- />
- )
- }
+ // function getDesigner () {
+ // return (
+ // file !== undefined &&
+ // <KaravanDesigner
+ // dark={false}
+ // key={"key"}
+ // filename={file.name}
+ // yaml={file.code}
+ // onSave={(name, yaml) => save(name, yaml)}
+ // onSaveCustomCode={(name, code) => post(new ProjectFile(name + ".java", project.projectId, code, Date.now()))}
+ // onGetCustomCode={(name, javaType) => {
+ // return new Promise<string | undefined>(resolve => resolve(files.filter(f => f.name === name + ".java")?.at(0)?.code))
+ // }}
+ // />
+ // )
+ // }
function getEditor () {
const language = file?.name.split('.').pop();
@@ -298,28 +202,6 @@ export const ProjectPage = (props: Props) => {
)
}
- function getProjectPanel() {
- return (
- <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
- {getProjectPanelTabs()}
- {getProjectPanelDetails()}
- </Flex>
- )
- }
-
- function getProjectPanelTabs() {
- return (
- <FlexItem className="project-tabs">
- <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}>
- <Tab eventKey="files" title="Files"/>
- <Tab eventKey="dashboard" title="Dashboard"/>
- <Tab eventKey="trace" title="Trace"/>
- <Tab eventKey="pipeline" title="Pipeline"/>
- </Tabs>
- </FlexItem>
- )
- }
-
function isBuildIn(): boolean {
return ['kamelets', 'templates'].includes(project.projectId);
}
@@ -332,25 +214,6 @@ export const ProjectPage = (props: Props) => {
return project.projectId === 'templates';
}
- function getProjectPanelDetails() {
- const buildIn = isBuildIn();
- return (
- <FlexItem>
- {buildIn && tab === 'files' && <FilesTab/>}
- {!buildIn &&
- <>
- {tab === 'files' && <FilesTab/>}
- {tab === 'dashboard' && project && <DashboardTab config={props.config}/>}
- {tab === 'trace' && project && <TraceTab config={props.config}/>}
- {tab === 'pipeline' && <ProjectPipelineTab project={project}
- needCommit={needCommit()}
- config={props.config}/>}
- </>
- }
- </FlexItem>
- )
- }
-
function getFilePanel() {
const isYaml = file !== undefined && file.name.endsWith("yaml");
const isIntegration = isYaml && file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code);
@@ -361,23 +224,24 @@ export const ProjectPage = (props: Props) => {
const showEditor = isCode || (isYaml && !isIntegration) || (isYaml && mode === 'code');
return (
<>
- {showDesigner && getDesigner()}
+ {/*{showDesigner && getDesigner()}*/}
{showEditor && getEditor()}
{isLog && getLogView()}
{isProperties && getPropertiesEditor()}
</>
)
}
+ console.log(operation, file)
const types = isBuildIn()
? (isKameletsProject() ? ['KAMELET'] : ['CODE', 'PROPERTIES'])
: ProjectFileTypes.filter(p => !['PROPERTIES', 'LOG', 'KAMELET'].includes(p.name)).map(p => p.name);
return (
<PageSection key={key} className="kamelet-section project-page" padding={{default: 'noPadding'}}>
<PageSection className="tools-section" padding={{default: 'noPadding'}}>
- <MainToolbar title={title()} tools={tools()}/>
+ <MainToolbar title={<ProjectTitle/>} tools={tools()}/>
</PageSection>
- {file === undefined && getProjectPanel()}
- {/*{file !== undefined && getFilePanel()}*/}
+ {file === undefined && operation !== 'select' && <ProjectPanel/>}
+ {file !== undefined && operation === 'select' && getFilePanel()}
<ProjectLog/>
<CreateFileModal types={types}/>
<DeleteFileModal />
diff --git a/karavan-app/src/main/webui/src/project/ProjectPanel.tsx b/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
new file mode 100644
index 00000000..8fa32f2d
--- /dev/null
+++ b/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
@@ -0,0 +1,49 @@
+import React, {useState} from 'react';
+import {
+ Flex,
+ FlexItem, Tabs, Tab
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {FilesTab} from "./files/FilesTab";
+import {useProjectStore} from "../api/ProjectStore";
+import {DashboardTab} from "./dashboard/DashboardTab";
+import {TraceTab} from "./trace/TraceTab";
+import {ProjectPipelineTab} from "./pipeline/ProjectPipelineTab";
+
+export const ProjectPanel = () => {
+
+ const [tab, setTab] = useState<string | number>('files');
+ const {project} = useProjectStore();
+
+ function isBuildIn(): boolean {
+ return ['kamelets', 'templates'].includes(project.projectId);
+ }
+
+ const buildIn = isBuildIn();
+ return (
+ <Flex direction={{default: "column"}} spaceItems={{default: "spaceItemsNone"}}>
+ <FlexItem className="project-tabs">
+ {buildIn && <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}>
+ <Tab eventKey="files" title="Files"/>
+ </Tabs>}
+ {!buildIn && <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}>
+ <Tab eventKey="files" title="Files"/>
+ <Tab eventKey="dashboard" title="Dashboard"/>
+ <Tab eventKey="trace" title="Trace"/>
+ <Tab eventKey="pipeline" title="Pipeline"/>
+ </Tabs>}
+ </FlexItem>
+ <FlexItem>
+ {buildIn && tab === 'files' && <FilesTab/>}
+ {!buildIn &&
+ <>
+ {tab === 'files' && <FilesTab/>}
+ {tab === 'dashboard' && project && <DashboardTab/>}
+ {tab === 'trace' && project && <TraceTab/>}
+ {tab === 'pipeline' && <ProjectPipelineTab/>}
+ </>
+ }
+ </FlexItem>
+ </Flex>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/project/ProjectTitle.tsx b/karavan-app/src/main/webui/src/project/ProjectTitle.tsx
new file mode 100644
index 00000000..f3c0c816
--- /dev/null
+++ b/karavan-app/src/main/webui/src/project/ProjectTitle.tsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import {
+ Badge,
+ Breadcrumb,
+ BreadcrumbItem,
+ Text,
+ TextContent,
+ Flex,
+ FlexItem,
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {getProjectFileType} from "../api/ProjectModels";
+import {useAppConfigStore, useFileStore, useProjectStore} from "../api/ProjectStore";
+
+export const ProjectTitle = () => {
+
+ const {project} = useProjectStore();
+ const {file, operation, setFile} = useFileStore();
+ const {config} = useAppConfigStore();
+
+ const isFile = file !== undefined;
+ const isLog = file !== undefined && file.name.endsWith("log");
+ const filename = file ? file.name.substring(0, file.name.lastIndexOf('.')) : "";
+ return (<div className="dsl-title project-title">
+ {isFile && <Flex direction={{default: "column"}} >
+ <FlexItem>
+ <Breadcrumb>
+ <BreadcrumbItem to="#" onClick={event => {
+ useFileStore.setState({file: undefined, operation: 'none'});
+ }}>
+ <div className={"project-breadcrumb"}>{project?.name + " (" + project?.projectId + ")"}</div>
+ </BreadcrumbItem>
+ </Breadcrumb>
+ </FlexItem>
+ <FlexItem>
+ <Flex direction={{default: "row"}}>
+ <FlexItem>
+ <Badge>{getProjectFileType(file)}</Badge>
+ </FlexItem>
+ <FlexItem>
+ <TextContent className="description">
+ <Text>{isLog ? filename : file.name}</Text>
+ </TextContent>
+ </FlexItem>
+ </Flex>
+ </FlexItem>
+ </Flex>}
+ {!isFile && <Flex direction={{default: "column"}} >
+ <FlexItem>
+ <TextContent className="title">
+ <Text component="h2">{project?.name + " (" + project?.projectId + ")"}</Text>
+ </TextContent>
+ </FlexItem>
+ <FlexItem>
+ <TextContent className="description">
+ <Text>{project?.description}</Text>
+ </TextContent>
+ </FlexItem>
+ </Flex>}
+ </div>)
+}
diff --git a/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx b/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
index 1957f9d6..0e7a75c4 100644
--- a/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
+++ b/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
@@ -31,19 +31,17 @@ import ReloadIcon from "@patternfly/react-icons/dist/esm/icons/bolt-icon";
import {RunnerToolbar} from "./RunnerToolbar";
import {Project, ProjectFile} from "../api/ProjectModels";
import {ProjectEventBus} from "../api/ProjectEventBus";
-import {useFileStore} from "../api/ProjectStore";
+import {useAppConfigStore, useFilesStore, useFileStore, useProjectStore} from "../api/ProjectStore";
interface Props {
project: Project,
needCommit: boolean,
isTemplates: boolean,
isKamelets: boolean,
- config: any,
file?: ProjectFile,
mode: "design" | "code",
editAdvancedProperties: boolean,
addProperty: () => void,
- download: () => void,
downloadImage: () => void,
setUploadModalOpen: () => void,
setEditAdvancedProperties: (checked: boolean) => void,
@@ -62,6 +60,9 @@ export const ProjectToolbar = (props: Props) => {
const [isRunning, setIsRunning] = useState(false);
const [isDeletingPod, setIsDeletingPod] = useState(false);
const [isReloadingPod, setIsReloadingPod] = useState(false);
+ const {project} = useProjectStore();
+ const {files} = useFilesStore();
+ const {config} = useAppConfigStore();
useEffect(() => {
const sub1 = ProjectEventBus.onCurrentRunner()?.subscribe((result) => {
@@ -73,6 +74,10 @@ export const ProjectToolbar = (props: Props) => {
};
});
+ function needCommit(): boolean {
+ return project ? files.filter(f => f.lastUpdate > project.lastCommitTimestamp).length > 0 : false;
+ }
+
function jbangRun() {
setJbangIsRunning(true);
KaravanApi.runProject(props.project, res => {
@@ -80,7 +85,7 @@ export const ProjectToolbar = (props: Props) => {
ProjectEventBus.setCurrentRunner(props.project.name);
setJbangIsRunning(false);
setPodName(res.data);
- ProjectEventBus.showLog('container', res.data, props.config.environment)
+ ProjectEventBus.showLog('container', res.data, config.environment)
} else {
// Todo notification
setJbangIsRunning(false);
@@ -164,7 +169,7 @@ export const ProjectToolbar = (props: Props) => {
}
function getTemplatesToolbar() {
- const {file,needCommit, editAdvancedProperties, download, setUploadModalOpen} = props;
+ const {file,needCommit, editAdvancedProperties, setUploadModalOpen} = props;
const isFile = file !== undefined;
const isProperties = file !== undefined && file.name.endsWith("properties");
return <Toolbar id="toolbar-group-types">
@@ -194,11 +199,7 @@ export const ProjectToolbar = (props: Props) => {
onChange={checked => props.setEditAdvancedProperties(checked)}
/>
</FlexItem>}
- {isFile && <FlexItem>
- <Tooltip content="Download source" position={"bottom-end"}>
- <Button isSmall variant="control" icon={<DownloadIcon/>} onClick={e => download()}/>
- </Tooltip>
- </FlexItem>}
+
{!isFile && <FlexItem>
<Button isSmall variant={"secondary"} icon={<PlusIcon/>}
onClick={e => ProjectEventBus.showCreateProjectModal(true)}>Create</Button>
@@ -214,8 +215,8 @@ export const ProjectToolbar = (props: Props) => {
}
function getProjectToolbar() {
- const {file,needCommit, mode, editAdvancedProperties, project, config,
- addProperty, setEditAdvancedProperties, download, downloadImage, setUploadModalOpen} = props;
+ const {file,needCommit, mode, editAdvancedProperties, project,
+ addProperty, setEditAdvancedProperties, downloadImage, setUploadModalOpen} = props;
const isFile = file !== undefined;
const isYaml = file !== undefined && file.name.endsWith("yaml");
const isIntegration = isYaml && file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code);
@@ -262,27 +263,14 @@ export const ProjectToolbar = (props: Props) => {
<Button isSmall variant="primary" icon={<PlusIcon/>} onClick={e => addProperty()}>Add property</Button>
</FlexItem>}
- {isFile && <FlexItem>
- <Tooltip content="Download source" position={"bottom-end"}>
- <Button isSmall variant="control" icon={<DownloadIcon/>} onClick={e => download()}/>
- </Tooltip>
- </FlexItem>}
+
{isIntegration && <FlexItem>
<Tooltip content="Download image" position={"bottom-end"}>
<Button isSmall variant="control" icon={<DownloadImageIcon/>} onClick={e => downloadImage()}/>
</Tooltip>
</FlexItem>}
- {!isFile && <FlexItem>
- <Button isSmall variant={"secondary"} icon={<PlusIcon/>}
- onClick={e => useFileStore.setState({operation:"create"})}>Create</Button>
- </FlexItem>}
- {!isFile && <FlexItem>
- <Button isSmall variant="secondary" icon={<UploadIcon/>}
- onClick={e => setUploadModalOpen()}>Upload</Button>
- </FlexItem>}
-
{isYaml && currentRunner === project.name && <FlexItem>
- <RunnerToolbar project={project} config={config} showConsole={false} reloadOnly={true} />
+ <RunnerToolbar project={project} showConsole={false} reloadOnly={true} />
</FlexItem>}
</Flex>
</ToolbarContent>
diff --git a/karavan-app/src/main/webui/src/project/RunnerToolbar.tsx b/karavan-app/src/main/webui/src/project/RunnerToolbar.tsx
index 4b63bf2b..e309a531 100644
--- a/karavan-app/src/main/webui/src/project/RunnerToolbar.tsx
+++ b/karavan-app/src/main/webui/src/project/RunnerToolbar.tsx
@@ -11,11 +11,11 @@ import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon
import {KaravanApi} from "../api/KaravanApi";
import {Project} from "../api/ProjectModels";
import {ProjectEventBus} from "../api/ProjectEventBus";
+import {useAppConfigStore} from "../api/ProjectStore";
interface Props {
project: Project,
- config: any,
showConsole: boolean,
reloadOnly: boolean
}
@@ -27,6 +27,7 @@ export const RunnerToolbar = (props: Props) => {
const [isRunning, setIsRunning] = useState(false);
const [isDeletingPod, setIsDeletingPod] = useState(false);
const [isReloadingPod, setIsReloadingPod] = useState(false);
+ const {config} = useAppConfigStore();
useEffect(() => {
const sub1 = ProjectEventBus.onCurrentRunner()?.subscribe((result) => {
@@ -44,7 +45,7 @@ export const RunnerToolbar = (props: Props) => {
ProjectEventBus.setCurrentRunner(props.project.name);
setJbangIsRunning(false);
setPodName(res.data);
- ProjectEventBus.showLog('container', res.data, props.config.environment)
+ ProjectEventBus.showLog('container', res.data, config.environment)
} else {
// Todo notification
setJbangIsRunning(false);
diff --git a/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx b/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
index 7eddf0c6..6f919cad 100644
--- a/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
+++ b/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
@@ -9,18 +9,14 @@ import {RunnerInfoContext} from "./RunnerInfoContext";
import {RunnerInfoMemory} from "./RunnerInfoMemory";
import {KaravanApi} from "../../api/KaravanApi";
import {PodStatus} from "../../api/ProjectModels";
-import {useProjectStore} from "../../api/ProjectStore";
+import {useAppConfigStore, useProjectStore} from "../../api/ProjectStore";
import {ProjectEventBus} from "../../api/ProjectEventBus";
export function isRunning(status: PodStatus): boolean {
return status.phase === 'Running' && !status.terminating;
}
-interface Props {
- config: any,
-}
-
-export const DashboardTab = (props: Props) => {
+export const DashboardTab = () => {
const {project, setProject} = useProjectStore();
const [podStatus, setPodStatus] = useState(new PodStatus());
@@ -28,6 +24,7 @@ export const DashboardTab = (props: Props) => {
const [memory, setMemory] = useState({});
const [jvm, setJvm] = useState({});
const [context, setContext] = useState({});
+ const {config} = useAppConfigStore();
useEffect(() => {
previousValue.current = podStatus;
@@ -47,10 +44,10 @@ export const DashboardTab = (props: Props) => {
if (res.status === 200) {
setPodStatus(res.data);
if (isRunning(res.data) && !isRunning(previousValue.current)) {
- ProjectEventBus.showLog('container', res.data.name, props.config.environment);
+ ProjectEventBus.showLog('container', res.data.name, config.environment);
}
} else {
- ProjectEventBus.showLog('container', name, props.config.environment, false);
+ ProjectEventBus.showLog('container', name, config.environment, false);
setPodStatus(new PodStatus({name: name}));
}
});
@@ -81,9 +78,8 @@ export const DashboardTab = (props: Props) => {
return podStatus.phase !== '';
}
- const {config} = props;
return (
- <PageSection className="project-bottom" padding={{default: "padding"}}>
+ <PageSection className="project-tab-panel" padding={{default: "padding"}}>
<Card className="project-development">
<CardBody>
<Flex direction={{default: "row"}}
@@ -93,11 +89,11 @@ export const DashboardTab = (props: Props) => {
</FlexItem>
<Divider orientation={{default: "vertical"}}/>
<FlexItem flex={{default: "flex_1"}}>
- <RunnerInfoMemory jvm={jvm} memory={memory} config={config} showConsole={showConsole()}/>
+ <RunnerInfoMemory jvm={jvm} memory={memory} showConsole={showConsole()}/>
</FlexItem>
<Divider orientation={{default: "vertical"}}/>
<FlexItem flex={{default: "flex_1"}}>
- <RunnerInfoContext context={context} config={config} showConsole={showConsole()}/>
+ <RunnerInfoContext context={context} showConsole={showConsole()}/>
</FlexItem>
</Flex>
</CardBody>
diff --git a/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoContext.tsx b/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoContext.tsx
index 62cc67ca..7683be64 100644
--- a/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoContext.tsx
+++ b/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoContext.tsx
@@ -14,12 +14,13 @@ import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
interface Props {
context: any,
- config: any,
showConsole: boolean
}
export const RunnerInfoContext = (props: Props) => {
+
+
function getContextInfo() {
return (
<LabelGroup numLabels={3}>
diff --git a/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoMemory.tsx b/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoMemory.tsx
index 15c37bd0..67e576ad 100644
--- a/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoMemory.tsx
+++ b/karavan-app/src/main/webui/src/project/dashboard/RunnerInfoMemory.tsx
@@ -15,7 +15,6 @@ import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
interface Props {
jvm: any,
memory: any,
- config: any,
showConsole: boolean
}
diff --git a/karavan-app/src/main/webui/src/project/files/FilesTab.tsx b/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
index feb57616..3ae79da5 100644
--- a/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
+++ b/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
@@ -6,14 +6,17 @@ import {
EmptyState,
EmptyStateVariant,
EmptyStateIcon,
- Title, PageSection, PanelHeader, Flex, FlexItem, Panel,
+ Title, PageSection, PanelHeader, Panel, Tooltip,
} from '@patternfly/react-core';
import '../../designer/karavan.css';
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 {useFilesStore, useFileStore} from "../../api/ProjectStore";
-import {getProjectFileType} from "../../api/ProjectModels";
+import {getProjectFileType, ProjectFile} from "../../api/ProjectModels";
+import {FileToolbar} from "./FilesToolbar";
+import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon";
+import FileSaver from "file-saver";
export const FilesTab = () => {
@@ -28,18 +31,20 @@ export const FilesTab = () => {
return "N/A"
}
}
+
+ function download (file: ProjectFile) {
+ if (file) {
+ const type = file.name.endsWith("yaml") ? "application/yaml;charset=utf-8" : undefined;
+ const f = new File([file.code], file.name, {type: type});
+ FileSaver.saveAs(f);
+ }
+ }
+
return (
- <PageSection className="project-bottom" padding={{default: "padding"}}>
+ <PageSection className="project-tab-panel" padding={{default: "padding"}}>
<Panel>
<PanelHeader>
- <Flex direction={{default: "row"}} justifyContent={{default:"justifyContentFlexEnd"}}>
- <FlexItem>
-
- </FlexItem>
- <FlexItem>
-
- </FlexItem>
- </Flex>
+ <FileToolbar/>
</PanelHeader>
</Panel>
<TableComposable aria-label="Files" variant={"compact"} className={"table"}>
@@ -79,6 +84,9 @@ export const FilesTab = () => {
<DeleteIcon/>
</Button>
}
+ <Tooltip content="Download source" position={"bottom-end"}>
+ <Button isSmall variant="plain" icon={<DownloadIcon/>} onClick={e => download(file)}/>
+ </Tooltip>
</Td>
</Tr>
})}
diff --git a/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx b/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
new file mode 100644
index 00000000..2ef4c092
--- /dev/null
+++ b/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import {
+ Button,
+ Flex,
+ FlexItem,
+} from '@patternfly/react-core';
+import '../../designer/karavan.css';
+import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {useFileStore} from "../../api/ProjectStore";
+
+export const FileToolbar = () => {
+
+ return <Flex className="toolbar" direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}}>
+ <FlexItem>
+ <Button isSmall variant={"secondary"} icon={<PlusIcon/>}
+ onClick={e => useFileStore.setState({operation:"create"})}>Create</Button>
+ </FlexItem>
+ <FlexItem>
+ <Button isSmall variant="secondary" icon={<UploadIcon/>}
+ onClick={e => useFileStore.setState({operation:"upload"})}>Upload</Button>
+ </FlexItem>
+ </Flex>
+}
diff --git a/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx b/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx
index 54cd6f99..6cd7e4fd 100644
--- a/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx
+++ b/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx
@@ -2,36 +2,22 @@ import React from 'react';
import '../../designer/karavan.css';
import {ProjectStatus} from "../ProjectStatus";
import {PageSection} from "@patternfly/react-core";
-import {Project} from "../../api/ProjectModels";
+import {useAppConfigStore, useProjectStore} from "../../api/ProjectStore";
-interface Props {
- project: Project,
- config: any,
- needCommit: boolean,
-}
-
-interface State {
- environment: string,
-}
-
-export class ProjectPipelineTab extends React.Component<Props, State> {
+export const ProjectPipelineTab = () => {
- public state: State = {
- environment: this.props.config.environment
- };
+ const {config} = useAppConfigStore();
+ const {project} = useProjectStore();
- render() {
- const {project, config,} = this.props;
- return (
- <PageSection className="project-bottom" padding={{default: "padding"}}>
- <div className="project-operations">
- {/*{["dev", "test", "prod"].map(env =>*/}
- {["dev"].map(env =>
- <ProjectStatus key={env} project={project} config={config} env={env}/>
- )}
- </div>
- </PageSection>
- )
- }
+ return (
+ <PageSection className="project-tab-panel" padding={{default: "padding"}}>
+ <div className="project-operations">
+ {/*{["dev", "test", "prod"].map(env =>*/}
+ {["dev"].map(env =>
+ <ProjectStatus key={env} project={project} config={config} env={env}/>
+ )}
+ </div>
+ </PageSection>
+ )
}
diff --git a/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx b/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
index 144c2b00..31f1c0c9 100644
--- a/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
+++ b/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
@@ -6,21 +6,18 @@ import {PodStatus} from "../../api/ProjectModels";
import {KaravanApi} from "../../api/KaravanApi";
import {ProjectEventBus} from "../../api/ProjectEventBus";
import {RunnerInfoTrace} from "./RunnerInfoTrace";
-import {useProjectStore} from "../../api/ProjectStore";
+import {useAppConfigStore, useProjectStore} from "../../api/ProjectStore";
export function isRunning(status: PodStatus): boolean {
return status.phase === 'Running' && !status.terminating;
}
-interface Props {
- config: any,
-}
-
-export const TraceTab = (props: Props) => {
+export const TraceTab = () => {
const {project, setProject} = useProjectStore();
const [trace, setTrace] = useState({});
const [refreshTrace, setRefreshTrace] = useState(true);
+ const {config} = useAppConfigStore();
useEffect(() => {
const sub2 = ProjectEventBus.onRefreshTrace()?.subscribe((result: boolean) => {
@@ -50,9 +47,8 @@ export const TraceTab = (props: Props) => {
}
}
- const {config} = props;
return (
- <PageSection className="project-bottom" padding={{default: "padding"}}>
+ <PageSection className="project-tab-panel" padding={{default: "padding"}}>
<RunnerInfoTrace trace={trace} refreshTrace={refreshTrace}/>
</PageSection>
)
diff --git a/karavan-app/src/main/webui/src/projects/CreateProjectModal.tsx b/karavan-app/src/main/webui/src/projects/CreateProjectModal.tsx
index 19fa2cb5..7f635a47 100644
--- a/karavan-app/src/main/webui/src/projects/CreateProjectModal.tsx
+++ b/karavan-app/src/main/webui/src/projects/CreateProjectModal.tsx
@@ -6,23 +6,21 @@ import {
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {useProjectStore} from "../api/ProjectStore";
+import {useAppConfigStore, useProjectStore} from "../api/ProjectStore";
import {ProjectService} from "../api/ProjectService";
import {Project} from "../api/ProjectModels";
import {QuarkusIcon, SpringIcon} from "../designer/utils/KaravanIcons";
import {CamelUi} from "../designer/utils/CamelUi";
-interface Props {
- config: any,
-}
-export const CreateProjectModal = (props: Props) => {
+export const CreateProjectModal = () => {
const {project, operation} = useProjectStore();
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [runtime, setRuntime] = useState('');
const [projectId, setProjectId] = useState('');
+ const {config} = useAppConfigStore();
function cleanValues() {
setName("");
@@ -48,7 +46,7 @@ export const CreateProjectModal = (props: Props) => {
}
}
- const runtimes = props.config.runtimes;
+ const runtimes = config.runtimes;
const isReady = projectId && name && description && !['templates', 'kamelets'].includes(projectId);
return (
<Modal
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index dec4ea29..5edf4006 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -22,14 +22,13 @@ import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
import {ProjectsTableRow} from "./ProjectsTableRow";
import {DeleteProjectModal} from "./DeleteProjectModal";
import {CreateProjectModal} from "./CreateProjectModal";
-import {useProjectsStore, useProjectStore} from "../api/ProjectStore";
+import {useAppConfigStore, useProjectsStore, useProjectStore} from "../api/ProjectStore";
import {ProjectService} from "../api/ProjectService";
import {MainToolbar} from "../common/MainToolbar";
import {Project} from "../api/ProjectModels";
interface Props {
- config: any,
toast: (title: string, text: string, variant: 'success' | 'danger' | 'warning' | 'info' | 'default') => void
}
@@ -39,6 +38,7 @@ export const ProjectsPage = (props: Props) => {
const {operation} = useProjectStore();
const [filter, setFilter] = useState<string>('');
const [loading, setLoading] = useState<boolean>(false);
+ const {config} = useAppConfigStore();
useEffect(() => {
const interval = setInterval(() => {
@@ -119,7 +119,6 @@ export const ProjectsPage = (props: Props) => {
{projs.map(project => (
<ProjectsTableRow
key={project.projectId}
- config={props.config}
project={project}/>
))}
{projs.length === 0 && getEmptyState()}
@@ -136,7 +135,7 @@ export const ProjectsPage = (props: Props) => {
<PageSection isFilled className="kamelets-page">
{getProjectsTable()}
</PageSection>
- {["create", "copy"].includes(operation) && <CreateProjectModal config={props.config}/>}
+ {["create", "copy"].includes(operation) && <CreateProjectModal/>}
{["delete"].includes(operation) && <DeleteProjectModal/>}
</PageSection>
)
diff --git a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
index 9ce6b07e..701d1424 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectsTableRow.tsx
@@ -10,20 +10,20 @@ import { Td, Tr} from "@patternfly/react-table";
import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
import CopyIcon from "@patternfly/react-icons/dist/esm/icons/copy-icon";
import {DeploymentStatus, Project} from '../api/ProjectModels';
-import {useDeploymentStatusesStore, useProjectStore} from "../api/ProjectStore";
+import {useAppConfigStore, useDeploymentStatusesStore, useProjectStore} from "../api/ProjectStore";
import {ProjectEventBus} from "../api/ProjectEventBus";
interface Props {
- config: any,
project: Project
}
export const ProjectsTableRow = (props: Props) => {
- const {statuses} = useDeploymentStatusesStore()
+ const {statuses} = useDeploymentStatusesStore();
+ const {config} = useAppConfigStore();
function getEnvironments(): string [] {
- return props.config.environments && Array.isArray(props.config.environments) ? Array.from(props.config.environments) : [];
+ return config.environments && Array.isArray(config.environments) ? Array.from(config.environments) : [];
}
function getDeploymentByEnvironments(name: string): [string, DeploymentStatus | undefined] [] {