Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"zustand": "^4.3.9"
},
"peerDependencies": {
"@kaoto/camel-catalog": "^0.2.2 || ^0.3.0",
"@kaoto/camel-catalog": "^0.2.2 || ^0.3.13",
"@patternfly/patternfly": "^6.4.0",
"@patternfly/react-code-editor": "^6.4.0",
"@patternfly/react-core": "^6.4.0",
Expand All @@ -98,7 +98,7 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.5",
"@eslint/js": "^9.10.0",
"@kaoto/camel-catalog": "^0.3.1",
"@kaoto/camel-catalog": "^0.3.13",
"@patternfly/patternfly": "^6.4.0",
"@patternfly/react-code-editor": "^6.4.0",
"@patternfly/react-core": "^6.4.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.custom-mode-toggle {
display: flex;
justify-content: flex-end;

span:has(svg) {
display: flex;
align-items: center;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { SchemaContext } from '@kaoto/forms';
import { render, screen } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';

import { CustomTableToggle } from './CustomTableToggle';

jest.mock('@kaoto/forms', () => ({
...jest.requireActual('@kaoto/forms'),
ObjectField: ({ propName }: { propName: string }) => (
<div data-testid={`object-field-${propName}`}>ObjectField: {propName}</div>
),
PropertiesField: ({ propName }: { propName: string }) => (
<div data-testid={`properties-field-${propName}`}>PropertiesField: {propName}</div>
),
ArrayFieldWrapper: ({ children, title }: { children: React.ReactNode; title: string }) => (
<div data-testid="array-field-wrapper">
<div data-testid="array-field-title">{title}</div>
{children}
</div>
),
}));

describe('CustomTableToggle', () => {
const schemaWithProperties = {
schema: {
properties: {
prop1: { type: 'string' as const },
prop2: { type: 'number' as const },
},
},
definitions: {},
};

const schemaWithoutProperties = {
schema: { properties: {} },
definitions: {},
};

const defaultProps = {
propName: 'testProp',
required: false,
};

describe('when schema has properties', () => {
it('should render toggle buttons with standard view by default', () => {
render(
<SchemaContext.Provider value={schemaWithProperties}>
<CustomTableToggle {...defaultProps} />
</SchemaContext.Provider>,
);

expect(screen.getByText('Standard')).toBeInTheDocument();
expect(screen.getByText('Custom')).toBeInTheDocument();
expect(screen.getByTestId('object-field-testProp')).toBeInTheDocument();
expect(screen.queryByTestId('array-field-wrapper')).not.toBeInTheDocument();

const standardButton = screen.getByTestId('testProp-standard-toggle').querySelector('button');
expect(standardButton).toHaveClass('pf-m-selected');
});

it('should switch to custom view and back', async () => {
const user = userEvent.setup();

render(
<SchemaContext.Provider value={schemaWithProperties}>
<CustomTableToggle {...defaultProps} />
</SchemaContext.Provider>,
);

// Switch to custom view
await user.click(screen.getByText('Custom'));
expect(screen.getByTestId('array-field-wrapper')).toBeInTheDocument();
expect(screen.getByTestId('array-field-title')).toHaveTextContent('Custom properties table');
expect(screen.getByTestId('properties-field-testProp')).toBeInTheDocument();
expect(screen.queryByTestId('object-field-testProp')).not.toBeInTheDocument();

const customButton = screen.getByTestId('testProp-custom-toggle').querySelector('button');
expect(customButton).toHaveClass('pf-m-selected');

// Switch back to standard view
await user.click(screen.getByText('Standard'));
expect(screen.getByTestId('object-field-testProp')).toBeInTheDocument();
expect(screen.queryByTestId('array-field-wrapper')).not.toBeInTheDocument();
});
});

describe('when schema has no properties', () => {
it('should render PropertiesField without toggle buttons', () => {
render(
<SchemaContext.Provider value={schemaWithoutProperties}>
<CustomTableToggle {...defaultProps} />
</SchemaContext.Provider>,
);

expect(screen.getByTestId('properties-field-testProp')).toBeInTheDocument();
expect(screen.queryByText('Standard')).not.toBeInTheDocument();
expect(screen.queryByText('Custom')).not.toBeInTheDocument();
});

it('should handle undefined properties object', () => {
const schemaWithUndefined = {
schema: { properties: undefined },
definitions: {},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;

render(
<SchemaContext.Provider value={schemaWithUndefined}>
<CustomTableToggle {...defaultProps} />
</SchemaContext.Provider>,
);

expect(screen.getByTestId('properties-field-testProp')).toBeInTheDocument();
expect(screen.queryByText('Standard')).not.toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import './CustomTableToggle.scss';

import { SettingsAdjust, TableSplit } from '@carbon/icons-react';
import { ArrayFieldWrapper, FieldProps, ObjectField, PropertiesField, SchemaContext } from '@kaoto/forms';
import { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
import { FunctionComponent, useCallback, useContext, useMemo, useState } from 'react';

export const CustomTableToggle: FunctionComponent<FieldProps> = ({ propName, required }) => {
const [activeView, setActiveView] = useState<'standard' | 'custom'>('standard');
const { schema } = useContext(SchemaContext);

const switchView = useCallback((view: 'standard' | 'custom') => {
setActiveView(view);
}, []);

const hasSchemaProperties = useMemo(() => {
const properties = schema.properties || {};
return Object.keys(properties).length > 0;
}, [schema]);

return hasSchemaProperties ? (
<>
<div>
<ToggleGroup isCompact aria-label="Mode toggle" className="custom-mode-toggle">
<ToggleGroupItem
icon={<SettingsAdjust />}
text="Standard"
buttonId="standard"
isSelected={activeView === 'standard'}
onChange={() => switchView('standard')}
data-testid={`${propName}-standard-toggle`}
/>
<ToggleGroupItem
icon={<TableSplit />}
text="Custom"
buttonId="custom"
isSelected={activeView === 'custom'}
onChange={() => switchView('custom')}
data-testid={`${propName}-custom-toggle`}
/>
</ToggleGroup>
</div>
<div>
{activeView === 'standard' && <ObjectField propName={propName} required={required} />}
{activeView === 'custom' && (
<ArrayFieldWrapper
propName={propName}
type="object"
title="Custom properties table"
description="Add new custom properties"
>
<PropertiesField propName={propName} required={required} />
</ArrayFieldWrapper>
)}
</div>
</>
) : (
<PropertiesField propName={propName} required={required} />
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CustomFieldsFactory, EnumField } from '@kaoto/forms';

import { CustomMediaTypes } from './ArrayBadgesField/CustomMediaTypes';
import { DataSourceBeanField, PrefixedBeanField, UnprefixedBeanField } from './BeanField/BeanField';
import { CustomTableToggle } from './CustomTableToggle/CustomTableToggle';
import { DirectEndpointNameField } from './DirectEndpointNameField';
import { ExpressionField } from './ExpressionField/ExpressionField';
import { MediaTypeField } from './MediaTypeField/MediaTypeField';
Expand All @@ -28,6 +29,8 @@ export const customFieldsFactoryfactory: CustomFieldsFactory = (schema) => {
return ExpressionField;
} else if (schema.type === 'array' && schema.title === 'Custom media types') {
return CustomMediaTypes;
} else if (schema.type === 'object' && schema.title === 'Endpoint Properties') {
return CustomTableToggle;
}

return undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ exports[`CamelComponentSchemaService getSchema should build the appropriate sche
"type": "string",
},
"parameters": {
"description": "The key-value pairs of the properties to configure this endpoint",
"title": "Endpoint Properties",
"type": "object",
},
"uri": {
Expand Down Expand Up @@ -74,7 +76,7 @@ exports[`CamelComponentSchemaService getSchema should build the appropriate sche
"type": "string",
},
"parameters": {
"description": "Endpoint properties description",
"description": "The key-value pairs of the properties to configure this endpoint",
"properties": {
"bootstrapServers": {
"description": "Comma separated list of Kafka Broker URLs",
Expand Down Expand Up @@ -163,7 +165,7 @@ exports[`CamelComponentSchemaService getSchema should build the appropriate sche
"type": "string",
},
"parameters": {
"description": "Endpoint properties description",
"description": "The key-value pairs of the properties to configure this endpoint",
"properties": {
"exchangeFormatter": {
"$comment": "group:advanced",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,14 +386,9 @@ export class CamelComponentSchemaService {
}),
);

if (catalogLookup.definition !== undefined && componentSchema !== undefined) {
schema.properties!.parameters = {
type: 'object',
title: 'Endpoint Properties',
description: 'Endpoint properties description',
properties: actualComponentProperties,
required: componentSchema.required,
};
if (catalogLookup.definition !== undefined && componentSchema !== undefined && schema.properties!.parameters) {
schema.properties!.parameters.properties = actualComponentProperties;
schema.properties!.parameters.required = componentSchema.required;
}
}

Expand Down
11 changes: 9 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3180,6 +3180,13 @@ __metadata:
languageName: node
linkType: hard

"@kaoto/camel-catalog@npm:^0.3.13":
version: 0.3.13
resolution: "@kaoto/camel-catalog@npm:0.3.13"
checksum: 10/223cd40a4bf8a09bd971ca7f6e02671c90e82a2eda30ecb3011f51a9fb16dcb835af409dbbdb983e5d425ea96d51ab3a6b7eb6c5104dbee31f1d87f1d59ec2c2
languageName: node
linkType: hard

"@kaoto/forms@npm:^1.6.0":
version: 1.6.0
resolution: "@kaoto/forms@npm:1.6.0"
Expand Down Expand Up @@ -3264,7 +3271,7 @@ __metadata:
"@carbon/icons-react": "npm:^11.67.0"
"@dnd-kit/core": "npm:^6.1.0"
"@eslint/js": "npm:^9.10.0"
"@kaoto/camel-catalog": "npm:^0.3.1"
"@kaoto/camel-catalog": "npm:^0.3.13"
"@kaoto/forms": "npm:^1.6.0"
"@kie-tools-core/editor": "npm:^10.0.0"
"@kie-tools-core/notifications": "npm:^10.0.0"
Expand Down Expand Up @@ -3345,7 +3352,7 @@ __metadata:
zundo: "npm:^2.3.0"
zustand: "npm:^4.3.9"
peerDependencies:
"@kaoto/camel-catalog": ^0.2.2 || ^0.3.0
"@kaoto/camel-catalog": ^0.2.2 || ^0.3.13
"@patternfly/patternfly": ^6.4.0
"@patternfly/react-code-editor": ^6.4.0
"@patternfly/react-core": ^6.4.0
Expand Down