Skip to content

Commit

Permalink
feat: Indication that some of the connectors mandatory properties are…
Browse files Browse the repository at this point in the history
… not yet configured

Fixes: #126
  • Loading branch information
igarashitm committed Jan 17, 2024
1 parent 1d2998c commit fb9cdb6
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export class CanvasService {
width: CanvasDefaults.DEFAULT_NODE_DIAMETER,
height: CanvasDefaults.DEFAULT_NODE_DIAMETER,
shape: CanvasDefaults.DEFAULT_NODE_SHAPE,
status: options.data?.vizNode?.getStatus(),
};
}

Expand Down
11 changes: 10 additions & 1 deletion packages/ui/src/components/Visualization/Custom/CustomNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,18 @@ interface CustomNodeProps extends WithSelectionProps {
const CustomNode: FunctionComponent<CustomNodeProps> = ({ element, ...rest }) => {
const vizNode = element.getData()?.vizNode;
const label = vizNode?.getNodeLabel();
const statusDecoratorTooltip = vizNode?.getStatusDecoratorTooltip();

return (
<DefaultNode element={element} label={label} truncateLength={15} {...rest} showStatusDecorator>
<DefaultNode
element={element}
label={label}
truncateLength={15}
{...rest}
showStatusDecorator
statusDecoratorTooltip={statusDecoratorTooltip}
onStatusDecoratorClick={() => {}}
>
<g data-testid={`custom-node__${vizNode?.id}`} data-nodelabel={label}>
<foreignObject
x="0"
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/src/hooks/entities.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ describe('useEntities', () => {
id: route-1234
from:
id: from-1234
uri: timer:template
uri: timer
parameters:
period: "1000"
timerName: template
steps:
- log:
id: log-1234
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ exports[`createCamelResource should create an empty KameletResource if no args i
"id": "from-1234",
"parameters": {
"period": "{{period}}",
"timerName": "user",
},
"steps": [
{
Expand All @@ -17,7 +18,7 @@ exports[`createCamelResource should create an empty KameletResource if no args i
"to": "kamelet:sink",
},
],
"uri": "timer:user",
"uri": "timer",
},
"id": "kamelet-1234",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ exports[`KameletResource should convert to JSON 1`] = `
"id": "from-1234",
"parameters": {
"period": "{{period}}",
"timerName": "user",
},
"steps": [
{
Expand All @@ -50,7 +51,7 @@ exports[`KameletResource should convert to JSON 1`] = `
"to": "kamelet:sink",
},
],
"uri": "timer:user",
"uri": "timer",
},
},
"types": {
Expand Down Expand Up @@ -103,6 +104,7 @@ exports[`KameletResource should create a new KameletResource 1`] = `
"id": "from-1234",
"parameters": {
"period": "{{period}}",
"timerName": "user",
},
"steps": [
{
Expand All @@ -112,7 +114,7 @@ exports[`KameletResource should create a new KameletResource 1`] = `
"to": "kamelet:sink",
},
],
"uri": "timer:user",
"uri": "timer",
},
},
"types": {
Expand Down Expand Up @@ -167,6 +169,7 @@ exports[`KameletResource should get the visual entities (Camel Route Visual Enti
"id": "from-1234",
"parameters": {
"period": "{{period}}",
"timerName": "user",
},
"steps": [
{
Expand All @@ -176,7 +179,7 @@ exports[`KameletResource should get the visual entities (Camel Route Visual Enti
"to": "kamelet:sink",
},
],
"uri": "timer:user",
"uri": "timer",
},
"id": "kamelet-1234",
},
Expand Down
9 changes: 9 additions & 0 deletions packages/ui/src/models/visualization/base-visual-entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { JSONSchemaType } from 'ajv';
import { DefinedComponent } from '../camel-catalog-index';
import { BaseCamelEntity, EntityType } from '../camel/entities';
import { NodeStatus } from '@patternfly/react-topology';

/**
* BaseVisualCamelEntity
Expand Down Expand Up @@ -94,6 +95,14 @@ export interface IVisualizationNode<T extends IVisualizationNodeData = IVisualiz
removeChild(): void;

populateLeafNodesIds(ids: string[]): void;

getStatus(): NodeStatus | undefined;

setStatus(status: NodeStatus): void;

getStatusDecoratorTooltip(): string | undefined;

setStatusDecoratorTooltip(tooltip: string): void;
}

export interface IVisualizationNodeData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ import {
ICamelElementLookupResult,
} from './support/camel-component-types';
import { EntityType } from '../../camel/entities';
import Ajv from 'ajv';
import { NodeStatus } from '@patternfly/react-topology';

export abstract class AbstractCamelVisualEntity implements BaseVisualCamelEntity {
constructor(public route: RouteDefinition) {}
constructor(public route: RouteDefinition) {
this.ajv = new Ajv({
allErrors: true,
useDefaults: true,
});
}

abstract id: string;
abstract type: EntityType;
abstract setId(id: string): void;
protected abstract getRootUri(): string | undefined;
protected ajv: Ajv;

getId(): string {
return this.id;
Expand Down Expand Up @@ -240,9 +248,34 @@ export abstract class AbstractCamelVisualEntity implements BaseVisualCamelEntity
childrenVizNodes.forEach((childVizNode) => vizNode.addChild(childVizNode));
});

this.setNodeStatus(path, vizNode);
return vizNode;
}

private setNodeStatus(path: string, vizNode: IVisualizationNode) {
const schema = this.getComponentSchema(path);
if (schema?.schema) {
const validator = this.ajv.compile(schema?.schema);
validator(get(this.route, path));
const missingProperties = validator.errors?.reduce((acc, error) => {
if (error.keyword === 'required' && error.params?.missingProperty) {
acc.push(error.params.missingProperty);
}
return acc;
}, [] as string[]);
if (missingProperties && missingProperties.length > 0) {
const message =
missingProperties.length > 1
? `${missingProperties.length} required properties are not yet configured: [ ${missingProperties} ]`
: `1 required property is not yet configured: [ ${missingProperties} ]`;
vizNode.setStatus(NodeStatus.warning);
vizNode.setStatusDecoratorTooltip(message);
} else {
vizNode.setStatus(NodeStatus.success);
}
}
}

private getVizNodesFromChildren(path: string, stepsProperty: CamelProcessorStepsProperties): IVisualizationNode[] {
let singlePath: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ spec:
template:
from:
id: ${getCamelRandomId('from')}
uri: "timer:user"
uri: "timer"
parameters:
timerName: user
period: "{{period}}"
steps:
- to: https://random-data-api.com/api/v2/users
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ export const routeTemplate = () => {
id: ${getCamelRandomId('route')}
from:
id: ${getCamelRandomId('from')}
uri: timer:template
uri: timer
parameters:
timerName: template
period: "1000"
steps:
- log:
Expand Down
19 changes: 19 additions & 0 deletions packages/ui/src/models/visualization/visualization-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
NodeInteraction,
VisualComponentSchema,
} from './base-visual-entity';
import { NodeStatus } from '@patternfly/react-topology';

export const createVisualizationNode = <T extends IVisualizationNodeData = IVisualizationNodeData>(
id: string,
Expand All @@ -24,6 +25,8 @@ class VisualizationNode<T extends IVisualizationNodeData = IVisualizationNodeDat
private previousNode: IVisualizationNode | undefined = undefined;
private nextNode: IVisualizationNode | undefined = undefined;
private children: IVisualizationNode[] | undefined;
private status: NodeStatus | undefined = undefined;
private statusDecoratorTooltip: string | undefined = undefined;

constructor(
public readonly id: string,
Expand Down Expand Up @@ -128,4 +131,20 @@ class VisualizationNode<T extends IVisualizationNodeData = IVisualizationNodeDat
/** If this node has children, populate the leaf nodes ids of each child */
this.children?.forEach((child) => child.populateLeafNodesIds(ids));
}

getStatus(): NodeStatus | undefined {
return this.status;
}

setStatus(status: NodeStatus) {
this.status = status;
}

getStatusDecoratorTooltip(): string | undefined {
return this.statusDecoratorTooltip;
}

setStatusDecoratorTooltip(tooltip: string) {
this.statusDecoratorTooltip = tooltip;
}
}

0 comments on commit fb9cdb6

Please sign in to comment.