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/10/26 00:59:41 UTC
[camel-karavan] 01/02: Kamelet Editor in App for #315
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 40d3914dd74b219fbd17e3a07780714a1f0d3172
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Wed Oct 25 20:42:16 2023 -0400
Kamelet Editor in App for #315
---
.../webui/src/knowledgebase/KnowledgebasePage.tsx | 22 +----
.../karavan-app/src/main/webui/src/main/Main.tsx | 6 +-
.../src/main/webui/src/project/ProjectPage.tsx | 2 +-
.../webui/src/project/files/CreateFileModal.tsx | 99 ++++++++++++++++++----
4 files changed, 91 insertions(+), 38 deletions(-)
diff --git a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
index 35368b54..02c6b641 100644
--- a/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/knowledgebase/KnowledgebasePage.tsx
@@ -16,21 +16,7 @@
*/
import React, {useState} from 'react';
import '../designer/karavan.css';
-import {
- Button,
- Flex,
- FlexItem,
- PageSection,
- Switch,
- Tab,
- Tabs,
- Text,
- TextContent,
- TextInput,
- Toolbar,
- ToolbarContent,
- ToolbarItem
-} from "@patternfly/react-core";
+import {Flex, FlexItem, PageSection, Switch, Tab, Tabs, Text, TextContent, TextInput, Toolbar, ToolbarContent, ToolbarItem} from "@patternfly/react-core";
import {MainToolbar} from "../designer/MainToolbar";
import {KameletsTab} from "./kamelets/KameletsTab";
import {EipTab} from "./eip/EipTab";
@@ -38,7 +24,6 @@ import {ComponentsTab} from "./components/ComponentsTab";
interface Props {
dark: boolean,
- onKameletsReload? (): void;
}
export const KnowledgebasePage = (props: Props) => {
@@ -56,11 +41,6 @@ export const KnowledgebasePage = (props: Props) => {
function getTools() {
return <Toolbar id="toolbar-group-types">
<ToolbarContent>
- {tab === 'kamelets' && <ToolbarItem>
- <Button
- onClick={(_event) => props.onKameletsReload?.()}
- >Reload</Button>
- </ToolbarItem>}
{tab === 'kamelets' && <ToolbarItem>
<Switch
label="Custom only"
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
index a2a8d5c9..a7a1e457 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
@@ -16,7 +16,7 @@
*/
import {Navigate, Route, Routes} from 'react-router-dom';
-import React, {useEffect, useRef} from "react";
+import React, {useEffect, useMemo, useRef} from "react";
import {KaravanApi} from "../api/KaravanApi";
import {
Bullseye,
@@ -132,6 +132,10 @@ export function Main() {
return !showStepper() && !showSpinner() && (KaravanApi.isAuthorized || KaravanApi.authType === 'public');
}
+ const projectPage = useMemo(() =>
+ <Route path="/projects/:projectId" element={<ProjectPage key={'project'}/>}/>
+ , []);
+
return (
<Page className="karavan">
{showSpinner() &&
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index 1df4f70e..43feee58 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -65,7 +65,7 @@ export function ProjectPage() {
}
const buildIn = isBuildIn();
-
+ console.log("Project refresh")
const showFilePanel = file !== undefined && operation === 'select';
return (
<PageSection className="project-page" padding={{default: 'noPadding'}}>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx b/karavan-web/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx
index 60723466..53473734 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/CreateFileModal.tsx
@@ -22,7 +22,9 @@ import {
FormGroup,
ModalVariant,
Form,
- ToggleGroupItem, ToggleGroup, FormHelperText, HelperText, HelperTextItem, TextInput
+ ToggleGroupItem, ToggleGroup, FormHelperText, HelperText, HelperTextItem, TextInput, Select,
+ SelectOption,
+ SelectList, MenuToggleElement, MenuToggle, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities,
} from '@patternfly/react-core';
import '../../designer/karavan.css';
import {Integration, KameletTypes, MetadataLabels} from "karavan-core/lib/model/IntegrationDefinition";
@@ -33,19 +35,23 @@ import {CamelUi} from "../../designer/utils/CamelUi";
import {ProjectService} from "../../api/ProjectService";
import {shallow} from "zustand/shallow";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
interface Props {
types: string[],
isKameletsProject: boolean
}
-export function CreateFileModal (props: Props) {
+export function CreateFileModal(props: Props) {
const [project] = useProjectStore((s) => [s.project], shallow);
const [operation, setFile] = useFileStore((s) => [s.operation, s.setFile], shallow);
- const [name, setName] = useState<string>( '');
+ const [name, setName] = useState<string>('');
const [fileType, setFileType] = useState<string>();
const [kameletType, setKameletType] = useState<KameletTypes>('source');
+ const [inputValue, setInputValue] = useState<string>();
+ const [selectIsOpen, setSelectIsOpen] = useState<boolean>(false);
+ const [selectedKamelet, setSelectedKamelet] = useState<[string, string]>(['', '']);
useEffect(() => {
if (props.types.length > 0) {
@@ -53,12 +59,12 @@ export function CreateFileModal (props: Props) {
}
}, [props]);
- function cleanValues() {
+ function cleanValues() {
setName("");
setFileType(props.types.at(0) || 'INTEGRATION');
}
- function closeModal () {
+ function closeModal() {
setFile("none");
cleanValues();
}
@@ -67,9 +73,10 @@ export function CreateFileModal (props: Props) {
if (fileType === 'INTEGRATION') {
return CamelDefinitionYaml.integrationToYaml(Integration.createNew(name, 'plain'));
} else if (fileType === 'KAMELET') {
- const kameletName = name + (isKamelet ? '-'+kameletType : '');
+ console.log(selectedKamelet, inputValue);
+ const kameletName = name + (isKamelet ? '-' + kameletType : '');
const integration = Integration.createNew(kameletName, 'kamelet');
- const meta:MetadataLabels = new MetadataLabels({"camel.apache.org/kamelet.type": kameletType});
+ const meta: MetadataLabels = new MetadataLabels({"camel.apache.org/kamelet.type": kameletType});
integration.metadata.labels = meta;
return CamelDefinitionYaml.integrationToYaml(integration);
} else {
@@ -77,12 +84,12 @@ export function CreateFileModal (props: Props) {
}
}
- function confirmAndCloseModal () {
+ function confirmAndCloseModal() {
const extension = ProjectFileTypes.filter(value => value.name === fileType)[0].extension;
const filename = (extension !== 'java') ? fileNameCheck(name) : CamelUi.javaNameFromTitle(name);
const code = getCode();
if (filename && extension) {
- const fullFileName = filename + (isKamelet ? '-'+kameletType : '') + '.' + extension;
+ const fullFileName = filename + (isKamelet ? '-' + kameletType : '') + '.' + extension;
const file = new ProjectFile(fullFileName, project.projectId, code, Date.now());
ProjectService.createFile(file);
cleanValues();
@@ -94,7 +101,7 @@ export function CreateFileModal (props: Props) {
}
}
- function fileNameCheck (title: string) {
+ function fileNameCheck(title: string) {
return title.replace(/[^0-9a-zA-Z.]+/gi, "-").toLowerCase();
}
@@ -103,10 +110,57 @@ export function CreateFileModal (props: Props) {
const filename = (extension !== 'java')
? fileNameCheck(name)
: CamelUi.javaNameFromTitle(name);
- const fullFileName = filename + (isKamelet ? '-'+kameletType : '') + '.' + extension;
+ const fullFileName = filename + (isKamelet ? '-' + kameletType : '') + '.' + extension;
+
+ const selectOptions: React.JSX.Element[] = []
+ KameletApi.getKamelets()
+ .filter(k => k.metadata.labels["camel.apache.org/kamelet.type"] === kameletType)
+ .filter(k => k.spec.definition.title.toLowerCase().includes(inputValue?.toLowerCase() || ''))
+ .forEach((kamelet) => {
+ const s = <SelectOption key={kamelet.metadata.name}
+ value={kamelet.metadata.name}
+ description={kamelet.spec.definition.title}
+ isFocused={kamelet.metadata.name === selectedKamelet[0]}
+ onClick={event => {
+ setSelectedKamelet([kamelet.metadata.name, kamelet.spec.definition.title]);
+ setSelectIsOpen(false);
+ setInputValue(kamelet.spec.definition.title)
+ }}
+ />;
+ selectOptions.push(s);
+ })
+
+
+ const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
+ <MenuToggle variant={"typeahead"}
+ isFullWidth
+ ref={toggleRef}
+ onClick={() => setSelectIsOpen(!selectIsOpen)}
+ isExpanded={selectIsOpen}
+ isDisabled={false}>
+ <TextInputGroup isPlain>
+ <TextInputGroupMain
+ value={inputValue}
+ onClick={event => {}}
+ onChange={(event, value) => {
+ setInputValue(value);
+ setSelectIsOpen(true)
+ }}
+ id="typeahead-select-input"
+ autoComplete="off"
+ // innerRef={textInputRef}
+ placeholder="Select Kamelet"
+ role="combobox"
+ isExpanded={selectIsOpen}
+ aria-controls="select-typeahead-listbox"
+ />
+ </TextInputGroup>
+ </MenuToggle>
+ );
+
return (
<Modal
- title="Create"
+ title={"Create " + (isKamelet ? "Kamelet" : "")}
variant={ModalVariant.small}
isOpen={["create", "copy"].includes(operation)}
onClose={closeModal}
@@ -123,13 +177,13 @@ export function CreateFileModal (props: Props) {
const title = p.title + ' (' + p.extension + ')';
return <ToggleGroupItem key={title} text={title} buttonId={p.name}
isSelected={fileType === p.name}
- onChange={(_, selected) => {
+ onChange={(_, selected) => {
setFileType(p.name);
}}/>
})}
</ToggleGroup>
</FormGroup>}
- {isKamelet && <FormGroup label="Kamelet Type" fieldId="kameletType" isRequired>
+ {isKamelet && <FormGroup label="Type" fieldId="kameletType" isRequired>
<ToggleGroup aria-label="Kamelet Type">
{['source', 'action', 'sink'].map((type) => {
const title = CamelUtil.capitalizeName(type);
@@ -137,18 +191,33 @@ export function CreateFileModal (props: Props) {
isSelected={kameletType === type}
onChange={(_, selected) => {
setKameletType(type as KameletTypes);
+ setSelectedKamelet(['', ''])
}}/>
})}
</ToggleGroup>
</FormGroup>}
<FormGroup label="Name" fieldId="name" isRequired>
<TextInput id="name" aria-label="name" value={name} onChange={(_, value) => setName(value)}/>
- <FormHelperText >
+ <FormHelperText>
<HelperText id="helper-text1">
<HelperTextItem variant={'default'}>{fullFileName}</HelperTextItem>
</HelperText>
</FormHelperText>
</FormGroup>
+ {isKamelet && <FormGroup label="Copy from" fieldId="kamelet">
+ <Select
+ aria-label={"Kamelet"}
+ onOpenChange={isOpen => setSelectIsOpen(false)}
+ isOpen={selectIsOpen}
+ aria-labelledby={"Kamelets"}
+ toggle={toggle}
+ shouldFocusToggleOnSelect
+ >
+ <SelectList>
+ {selectOptions}
+ </SelectList>
+ </Select>
+ </FormGroup>}
</Form>
</Modal>
)