diff --git a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessor.java b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessor.java index be986bd53..0f2cabfc1 100644 --- a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessor.java +++ b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessor.java @@ -217,7 +217,7 @@ public String getDataFormatCatalog() throws Exception { eipModelOptions = eipModel.getOptions(); } - sortPropertiesAccordingToCamelCatalog(dataFormatSchema, eipModelOptions); + sortPropertiesAccordingToCamelCatalog(dataFormatSchema, eipModelOptions); var dataFormatCatalog = (EipModel) camelCatalog.model(Kind.eip, dataFormatName); if (dataFormatCatalog == null) { @@ -260,7 +260,7 @@ public String getLanguageCatalog() throws Exception { eipModelOptions = eipModel.getOptions(); } - sortPropertiesAccordingToCamelCatalog(languageSchema, eipModelOptions); + sortPropertiesAccordingToCamelCatalog(languageSchema, eipModelOptions); var languageCatalog = (EipModel) camelCatalog.model(Kind.eip, languageName); if (languageCatalog == null) { @@ -362,12 +362,17 @@ public String getPatternCatalog() throws Exception { continue; } + sortedSchemaProperties.set(propertyName, propertySchema); + var catalogOpOptional = eipModel.getOptions().stream() .filter(op -> op.getName().equals(propertyName)).findFirst(); + if (catalogOpOptional.isEmpty()) { - throw new Exception( + LOGGER.warning( String.format("Option '%s' not found for processor '%s'", propertyName, processorFQCN)); + continue; } + var catalogOp = catalogOpOptional.get(); if ("object".equals(catalogOp.getType()) && !catalogOp.getJavaType().startsWith("java.util.Map") && !propertySchema.has("$comment")) { @@ -383,8 +388,6 @@ public String getPatternCatalog() throws Exception { } else if (catalogOp.getGroup() != null) { propertySchema.put("group", catalogOp.getGroup()); } - - sortedSchemaProperties.set(propertyName, propertySchema); } var json = JsonMapper.asJsonObject(eipModel).toJson(); diff --git a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelYamlDslSchemaProcessor.java b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelYamlDslSchemaProcessor.java index 53f961b99..10a79fa60 100644 --- a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelYamlDslSchemaProcessor.java +++ b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CamelYamlDslSchemaProcessor.java @@ -32,6 +32,7 @@ public class CamelYamlDslSchemaProcessor { private static final String PROCESSOR_DEFINITION = "org.apache.camel.model.ProcessorDefinition"; private static final String TOKENIZER_DEFINITION = "org.apache.camel.model.TokenizerDefinition"; private static final String ROUTE_CONFIGURATION_DEFINITION = "org.apache.camel.model.RouteConfigurationDefinition"; + private static final String REST_DEFINITION = "org.apache.camel.model.rest.RestDefinition"; private static final String LOAD_BALANCE_DEFINITION = "org.apache.camel.model.LoadBalanceDefinition"; private static final String EXPRESSION_SUB_ELEMENT_DEFINITION = "org.apache.camel.model.ExpressionSubElementDefinition"; @@ -58,7 +59,20 @@ public class CamelYamlDslSchemaProcessor { "org.apache.camel.model.ToDefinition", List.of("uri", "parameters"), "org.apache.camel.model.WireTapDefinition", - List.of("uri", "parameters")); + List.of("uri", "parameters"), + "org.apache.camel.model.rest.GetDefinition", + List.of("to"), + "org.apache.camel.model.rest.PostDefinition", + List.of("to"), + "org.apache.camel.model.rest.PutDefinition", + List.of("to"), + "org.apache.camel.model.rest.DeleteDefinition", + List.of("to"), + "org.apache.camel.model.rest.HeadDefinition", + List.of("to"), + "org.apache.camel.model.rest.PatchDefinition", + List.of("to")); + private final List processorReferenceBlockList = List.of(PROCESSOR_DEFINITION); public CamelYamlDslSchemaProcessor(ObjectMapper mapper, ObjectNode yamlDslSchema) throws Exception { @@ -269,6 +283,7 @@ public Map getProcessors() throws Exception { .withObject(PROCESSOR_DEFINITION) .withObject("/properties"); addRouteConfigurationProcessors(relocatedDefinitions, processors); + addRestProcessors(relocatedDefinitions, processors); var answer = new LinkedHashMap(); for (var processorEntry : processors) { @@ -354,6 +369,24 @@ private void addRouteConfigurationProcessors(ObjectNode relocatedDefinitions, Ob processors.setAll(onCompletionProcessor); } + private void addRestProcessors(ObjectNode relocatedDefinitions, ObjectNode processors) { + var restProcessor = relocatedDefinitions + .withObject(REST_DEFINITION) + .withObject("/properties"); + var restGetProcessor = restProcessor.withObject("get").withObject("items"); + var restPostProcessor = restProcessor.withObject("post").withObject("items"); + var restPutProcessor = restProcessor.withObject("put").withObject("items"); + var restDeleteProcessor = restProcessor.withObject("delete").withObject("items"); + var restHeadProcessor = restProcessor.withObject("head").withObject("items"); + var restPatchProcessor = restProcessor.withObject("patch").withObject("items"); + processors.set("get", restGetProcessor); + processors.set("post", restPostProcessor); + processors.set("put", restPutProcessor); + processors.set("delete", restDeleteProcessor); + processors.set("head", restHeadProcessor); + processors.set("patch", restPatchProcessor); + } + private ObjectNode extractFromOneOf(String name, ObjectNode definition) throws Exception { if (!definition.has("oneOf")) { return definition; diff --git a/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessorTest.java b/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessorTest.java index 2d8d6810a..a3a2806b6 100644 --- a/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessorTest.java +++ b/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/generator/CamelCatalogProcessorTest.java @@ -175,6 +175,35 @@ void testGetDataFormatCatalog() throws Exception { assertEquals(1, customPropertiesSchemaRequiredFields.size(), "Size should be 1"); } + @Test + void testRestProcessors() throws Exception { + var restGetProcessorSchema = processorCatalog + .withObject("/get") + .withObject("propertiesSchema"); + var restPostProcessorSchema = processorCatalog + .withObject("/post") + .withObject("propertiesSchema"); + var restPutProcessorSchema = processorCatalog + .withObject("/put") + .withObject("propertiesSchema"); + var restDeleteProcessorSchema = processorCatalog + .withObject("/delete") + .withObject("propertiesSchema"); + var restHeadProcessorSchema = processorCatalog + .withObject("/head") + .withObject("propertiesSchema"); + var restPatchProcessorSchema = processorCatalog + .withObject("/patch") + .withObject("propertiesSchema"); + + assertFalse(restGetProcessorSchema.isEmpty(), "get processor schema should not be empty"); + assertFalse(restPostProcessorSchema.isEmpty(), "post processor schema should not be empty"); + assertFalse(restPutProcessorSchema.isEmpty(), "put processor schema should not be empty"); + assertFalse(restDeleteProcessorSchema.isEmpty(), "delete processor schema should not be empty"); + assertFalse(restHeadProcessorSchema.isEmpty(), "head processor schema should not be empty"); + assertFalse(restPatchProcessorSchema.isEmpty(), "patch processor schema should not be empty"); + } + @Test void testDataFormatEnumParameter() throws Exception { checkEnumParameters(dataFormatCatalog); diff --git a/packages/ui/src/models/camel/camel-route-resource.ts b/packages/ui/src/models/camel/camel-route-resource.ts index 238d93865..903a747a0 100644 --- a/packages/ui/src/models/camel/camel-route-resource.ts +++ b/packages/ui/src/models/camel/camel-route-resource.ts @@ -1,5 +1,7 @@ import { CamelYamlDsl, RouteDefinition } from '@kaoto/camel-catalog/types'; import { TileFilter } from '../../components/Catalog'; +import { YamlCamelResourceSerializer } from '../../serializers'; +import { CamelResourceSerializer } from '../../serializers/camel-resource-serializer'; import { createCamelPropertiesSorter, isDefined } from '../../utils'; import { CatalogKind } from '../catalog-kind'; import { AddStepMode, BaseVisualCamelEntityConstructor } from '../visualization/base-visual-entity'; @@ -11,6 +13,7 @@ import { CamelInterceptVisualEntity } from '../visualization/flows/camel-interce import { CamelOnCompletionVisualEntity } from '../visualization/flows/camel-on-completion-visual-entity'; import { CamelOnExceptionVisualEntity } from '../visualization/flows/camel-on-exception-visual-entity'; import { CamelRestConfigurationVisualEntity } from '../visualization/flows/camel-rest-configuration-visual-entity'; +import { CamelRestVisualEntity } from '../visualization/flows/camel-rest-visual-entity'; import { CamelRouteConfigurationVisualEntity } from '../visualization/flows/camel-route-configuration-visual-entity'; import { NonVisualEntity } from '../visualization/flows/non-visual-entity'; import { CamelComponentFilterService } from '../visualization/flows/support/camel-component-filter.service'; @@ -20,8 +23,6 @@ import { BeansEntity, isBeans } from '../visualization/metadata'; import { BaseVisualCamelEntityDefinition, BeansAwareResource, CamelResource } from './camel-resource'; import { BaseCamelEntity, EntityType } from './entities'; import { SourceSchemaType } from './source-schema-type'; -import { CamelResourceSerializer } from '../../serializers/camel-resource-serializer'; -import { YamlCamelResourceSerializer } from '../../serializers'; export class CamelRouteResource implements CamelResource, BeansAwareResource { static readonly SUPPORTED_ENTITIES: { type: EntityType; group: string; Entity: BaseVisualCamelEntityConstructor }[] = @@ -39,6 +40,7 @@ export class CamelRouteResource implements CamelResource, BeansAwareResource { { type: EntityType.OnException, group: 'Error Handling', Entity: CamelOnExceptionVisualEntity }, { type: EntityType.ErrorHandler, group: 'Error Handling', Entity: CamelErrorHandlerVisualEntity }, { type: EntityType.RestConfiguration, group: 'Rest', Entity: CamelRestConfigurationVisualEntity }, + { type: EntityType.Rest, group: 'Rest', Entity: CamelRestVisualEntity }, ]; static readonly PARAMETERS_ORDER = ['id', 'description', 'uri', 'parameters', 'steps']; private static readonly ERROR_RELATED_ENTITIES = [EntityType.OnException, EntityType.ErrorHandler]; diff --git a/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts index d9b4fc8ab..8326a49a5 100644 --- a/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts @@ -151,8 +151,8 @@ export class CamelRestConfigurationVisualEntity implements BaseVisualCamelEntity return restConfigurationGroupNode; } - toJSON(): unknown { - return this.restConfigurationDef; + toJSON(): { restConfiguration: RestConfiguration } { + return { restConfiguration: this.restConfigurationDef.restConfiguration }; } private getValidatorFunction( diff --git a/packages/ui/src/models/visualization/flows/camel-rest-visual-entity.test.ts b/packages/ui/src/models/visualization/flows/camel-rest-visual-entity.test.ts new file mode 100644 index 000000000..dc9c76705 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/camel-rest-visual-entity.test.ts @@ -0,0 +1,202 @@ +import catalogLibrary from '@kaoto/camel-catalog/index.json'; +import { CatalogLibrary, Rest } from '@kaoto/camel-catalog/types'; +import { restStub } from '../../../stubs/rest'; +import { getFirstCatalogMap } from '../../../stubs/test-load-catalog'; +import { EntityType } from '../../camel/entities'; +import { CatalogKind } from '../../catalog-kind'; +import { CamelCatalogService } from './camel-catalog.service'; +import { CamelRestVisualEntity } from './camel-rest-visual-entity'; +import { KaotoSchemaDefinition } from '../../kaoto-schema'; +import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; + +describe('CamelRestVisualEntity', () => { + const REST_ID_REGEXP = /^rest-[a-zA-Z0-9]{4}$/; + let restDef: { rest: Rest }; + let restSchema: KaotoSchemaDefinition['schema']; + + beforeAll(async () => { + const catalogsMap = await getFirstCatalogMap(catalogLibrary as CatalogLibrary); + CamelCatalogService.setCatalogKey(CatalogKind.Entity, catalogsMap.entitiesCatalog); + restSchema = catalogsMap.entitiesCatalog[EntityType.Rest].propertiesSchema as KaotoSchemaDefinition['schema']; + }); + + afterAll(() => { + CamelCatalogService.clearCatalogs(); + }); + + beforeEach(() => { + restDef = { + rest: { + ...restStub.rest, + }, + }; + }); + + describe('isApplicable', () => { + it.each([ + [true, { rest: {} }], + [true, { rest: { bindingMode: 'off' } }], + [true, restStub], + [false, { from: { id: 'from-1234', steps: [] } }], + [false, { rest: { bindingMode: 'off' }, anotherProperty: true }], + ])('should return %s for %s', (result, definition) => { + expect(CamelRestVisualEntity.isApplicable(definition)).toEqual(result); + }); + }); + + describe('constructor', () => { + it('should set id to generated id', () => { + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.id).toMatch(REST_ID_REGEXP); + }); + }); + + it('should return id', () => { + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.getId()).toMatch(REST_ID_REGEXP); + }); + + it('should set id', () => { + const entity = new CamelRestVisualEntity(restDef); + const newId = 'newId'; + entity.setId(newId); + + expect(entity.getId()).toEqual(newId); + }); + + it('should delegate to super return node label', () => { + const superGetNodeLabelSpy = jest + .spyOn(AbstractCamelVisualEntity.prototype, 'getNodeLabel') + .mockReturnValueOnce('label'); + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.getNodeLabel()).toEqual('label'); + expect(superGetNodeLabelSpy).toHaveBeenCalled(); + }); + + it('should delegate to super return node tooltip', () => { + const superGetNodeLabelSpy = jest + .spyOn(AbstractCamelVisualEntity.prototype, 'getTooltipContent') + .mockReturnValueOnce('tooltip'); + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.getTooltipContent()).toEqual('tooltip'); + expect(superGetNodeLabelSpy).toHaveBeenCalled(); + }); + + describe('getComponentSchema', () => { + it('should return entity current definition', () => { + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.getComponentSchema(CamelRestVisualEntity.ROOT_PATH)?.definition).toEqual(restDef.rest); + }); + + it('should return schema from store', () => { + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.getComponentSchema(CamelRestVisualEntity.ROOT_PATH)?.schema).toEqual(restSchema); + }); + }); + + describe('updateModel', () => { + it('should update model', () => { + const entity = new CamelRestVisualEntity(restDef); + const path = 'rest.bindingMode'; + const value = 'json'; + + entity.updateModel(path, value); + + expect(restDef.rest.bindingMode).toEqual(value); + }); + + it('should not update model if path is not defined', () => { + const entity = new CamelRestVisualEntity(restDef); + const value = 'json_xml'; + + entity.updateModel(undefined, value); + + expect(restDef.rest.bindingMode).toEqual('auto'); + }); + + it('should reset the rest object if it is not defined', () => { + const entity = new CamelRestVisualEntity(restDef); + + entity.updateModel('rest', {}); + + expect(restDef.rest).toEqual({}); + }); + }); + + it('return no interactions', () => { + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.getNodeInteraction()).toEqual({ + canHavePreviousStep: false, + canHaveNextStep: false, + canHaveChildren: false, + canHaveSpecialChildren: false, + canRemoveStep: false, + canReplaceStep: false, + canRemoveFlow: true, + canBeDisabled: false, + }); + }); + + describe('getNodeValidationText', () => { + it('should return undefined for valid definitions', () => { + const entity = new CamelRestVisualEntity({ + rest: { + ...restDef.rest, + bindingMode: 'json', + }, + }); + + expect(entity.getNodeValidationText()).toBeUndefined(); + }); + + it('should not modify the original definition when validating', () => { + const originalRestDef: Rest = { ...restDef.rest }; + const entity = new CamelRestVisualEntity(restDef); + + entity.getNodeValidationText(); + + expect(restDef.rest).toEqual(originalRestDef); + }); + + it('should NOT return errors when there is an invalid property', () => { + const invalidRestDef: Rest = { + ...restDef.rest, + bindingMode: 'true' as unknown as Rest['bindingMode'], + openApi: 'true' as unknown as Rest['openApi'], + }; + const entity = new CamelRestVisualEntity({ rest: invalidRestDef }); + + expect(entity.getNodeValidationText()).toBeUndefined(); + }); + }); + + describe('toVizNode', () => { + it('should return visualization node', () => { + const entity = new CamelRestVisualEntity(restDef); + + const vizNode = entity.toVizNode(); + + expect(vizNode.data).toEqual({ + componentName: undefined, + entity, + icon: '', + isGroup: true, + path: 'rest', + processorName: 'rest', + }); + }); + }); + + it('should serialize the rest definition', () => { + const entity = new CamelRestVisualEntity(restDef); + + expect(entity.toJSON()).toEqual(restDef); + }); +}); diff --git a/packages/ui/src/models/visualization/flows/camel-rest-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-rest-visual-entity.ts new file mode 100644 index 000000000..40912a269 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/camel-rest-visual-entity.ts @@ -0,0 +1,130 @@ +import { ProcessorDefinition, Rest } from '@kaoto/camel-catalog/types'; +import { getCamelRandomId } from '../../../camel-utils/camel-random-id'; +import { SchemaService } from '../../../components/Form/schema.service'; +import { NodeIconResolver, NodeIconType, getValue, isDefined, setValue } from '../../../utils'; +import { EntityType } from '../../camel/entities/base-entity'; +import { CatalogKind } from '../../catalog-kind'; +import { + BaseVisualCamelEntity, + IVisualizationNode, + IVisualizationNodeData, + NodeInteraction, + VisualComponentSchema, +} from '../base-visual-entity'; +import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; +import { CamelCatalogService } from './camel-catalog.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; +import { CamelComponentFilterService } from './support/camel-component-filter.service'; + +export class CamelRestVisualEntity extends AbstractCamelVisualEntity<{ rest: Rest }> implements BaseVisualCamelEntity { + id: string; + readonly type = EntityType.Rest; + static readonly ROOT_PATH = 'rest'; + private readonly OMIT_FORM_FIELDS = [ + ...SchemaService.OMIT_FORM_FIELDS, + 'get', + 'post', + 'put', + 'delete', + 'head', + 'patch', + ]; + + constructor(public restDef: { rest: Rest } = { rest: {} }) { + super(restDef); + const id = restDef.rest.id ?? getCamelRandomId(CamelRestVisualEntity.ROOT_PATH); + this.id = id; + this.restDef.rest.id = id; + } + + static isApplicable(restDef: unknown): restDef is { rest: Rest } { + if (!isDefined(restDef) || Array.isArray(restDef) || typeof restDef !== 'object') { + return false; + } + + const objectKeys = Object.keys(restDef!); + + return objectKeys.length === 1 && this.ROOT_PATH in restDef! && typeof restDef.rest === 'object'; + } + + getRootPath() { + return CamelRestVisualEntity.ROOT_PATH; + } + + setId(id: string): void { + this.id = id; + } + + getComponentSchema(path?: string): VisualComponentSchema | undefined { + if (path === CamelRestVisualEntity.ROOT_PATH) { + return { + definition: Object.assign({}, this.restDef.rest), + schema: CamelCatalogService.getComponent(CatalogKind.Entity, 'rest')?.propertiesSchema ?? {}, + }; + } + + /** If we're targetting a Rest method, the path would be `rest.get.0` */ + const method = path?.split('.')[1] ?? ''; + if (isDefined(path) && CamelComponentFilterService.REST_DSL_METHODS.includes(method)) { + return { + definition: Object.assign({}, getValue(this.restDef, path)), + schema: CamelCatalogService.getComponent(CatalogKind.Pattern, method)?.propertiesSchema ?? {}, + }; + } + + return super.getComponentSchema(path); + } + + getOmitFormFields(): string[] { + return this.OMIT_FORM_FIELDS; + } + + updateModel(path: string | undefined, value: unknown): void { + if (!path) return; + + setValue(this.restDef, path, value); + + if (!isDefined(this.restDef.rest)) { + this.restDef.rest = {}; + } + } + + getNodeInteraction(): NodeInteraction { + return { + canHavePreviousStep: false, + canHaveNextStep: false, + canHaveChildren: false, + /** Replace it with `true` when enabling the methods (GET, POST, PUT) */ + canHaveSpecialChildren: false, + canRemoveStep: false, + canReplaceStep: false, + canRemoveFlow: true, + canBeDisabled: false, + }; + } + + getNodeValidationText(): string | undefined { + return undefined; + } + + toVizNode(): IVisualizationNode { + const restGroupNode = NodeMapperService.getVizNode( + this.getRootPath(), + { processorName: 'rest' as keyof ProcessorDefinition }, + this.restDef, + ); + restGroupNode.data.entity = this; + restGroupNode.data.isGroup = true; + restGroupNode.data.icon = NodeIconResolver.getIcon(this.type, NodeIconType.VisualEntity); + + return restGroupNode; + } + + toJSON(): { rest: Rest } { + return { rest: this.restDef.rest }; + } + + protected getRootUri(): string | undefined { + return undefined; + } +} diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts index b3e8ee1b3..e7939c1ec 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts @@ -182,6 +182,14 @@ export class CamelComponentDefaultService { parameters: {} `); + case 'delete' as keyof ProcessorDefinition: + case 'get' as keyof ProcessorDefinition: + case 'head' as keyof ProcessorDefinition: + case 'patch' as keyof ProcessorDefinition: + case 'post' as keyof ProcessorDefinition: + case 'put' as keyof ProcessorDefinition: + return { id: getCamelRandomId(processorName) } as ProcessorDefinition; + default: return { [processorName]: { diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-filter.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-filter.service.ts index 364acd1e5..a71bb9f01 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-filter.service.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-filter.service.ts @@ -4,6 +4,7 @@ import { AddStepMode } from '../../base-visual-entity'; import { CamelRouteVisualEntityData } from './camel-component-types'; export class CamelComponentFilterService { + static readonly REST_DSL_METHODS = ['delete', 'get', 'head', 'patch', 'post', 'put']; private static SPECIAL_CHILDREN = [ 'when', 'otherwise', @@ -14,6 +15,7 @@ export class CamelComponentFilterService { 'interceptSendToEndpoint', 'onException', 'onCompletion', + ...this.REST_DSL_METHODS, ]; static getCamelCompatibleComponents( @@ -46,6 +48,7 @@ export class CamelComponentFilterService { choice: ['when'], doTry: ['doCatch'], routeConfiguration: ['intercept', 'interceptFrom', 'interceptSendToEndpoint', 'onException', 'onCompletion'], + rest: this.REST_DSL_METHODS, }; /** If an `otherwise` or a `doFinally` already exists, we shouldn't offer it in the catalog */ diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts index 38f9fafd4..3cf938887 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts @@ -14,6 +14,7 @@ import { KaotoSchemaDefinition } from '../../../kaoto-schema'; import { NodeLabelType } from '../../../settings/settings.model'; import { VisualComponentSchema } from '../../base-visual-entity'; import { CamelCatalogService } from '../camel-catalog.service'; +import { CamelComponentFilterService } from './camel-component-filter.service'; import { CamelProcessorStepsProperties, ICamelElementLookupResult } from './camel-component-types'; export class CamelComponentSchemaService { @@ -30,6 +31,7 @@ export class CamelComponentSchemaService { 'interceptSendToEndpoint', 'onException', 'onCompletion', + ...CamelComponentFilterService.REST_DSL_METHODS, ]; static DISABLED_REMOVE_STEPS = ['from', 'route'] as unknown as (keyof ProcessorDefinition)[]; @@ -216,6 +218,9 @@ export class CamelComponentSchemaService { { name: 'onCompletion', type: 'array-clause' }, ]; + case 'rest' as keyof ProcessorDefinition: + return CamelComponentFilterService.REST_DSL_METHODS.map((method) => ({ name: method, type: 'array-clause' })); + default: return []; } diff --git a/packages/ui/src/models/visualization/flows/templates/rest.ts b/packages/ui/src/models/visualization/flows/templates/rest.ts new file mode 100644 index 000000000..f0bf09ea6 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/templates/rest.ts @@ -0,0 +1,8 @@ +import { getCamelRandomId } from '../../../../camel-utils/camel-random-id'; + +export const restTemplate = () => { + return `- rest: + id: ${getCamelRandomId('rest')} + openApi: + specification: petstore-v3.json`; +}; diff --git a/packages/ui/src/stubs/rest.ts b/packages/ui/src/stubs/rest.ts new file mode 100644 index 000000000..95905e2b9 --- /dev/null +++ b/packages/ui/src/stubs/rest.ts @@ -0,0 +1,11 @@ +import { Rest } from '@kaoto/camel-catalog/types'; + +export const restStub: { rest: Rest } = { + rest: { + id: 'rest-1234', + bindingMode: 'auto', + openApi: { + specification: 'https://api.example.com/openapi.json', + }, + }, +};