Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 0603c3f

Browse files
BoykoAlexghillert
authored andcommitted
Code-editor for Scriptable-Transform script property
1 parent d5f124f commit 0603c3f

File tree

11 files changed

+206
-37
lines changed

11 files changed

+206
-37
lines changed

ui/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@
3737
"ngx-pagination": "3.0.1",
3838
"rxjs": "5.5.2",
3939
"sockjs-client": "1.1.4",
40-
"spring-flo": "git://github.com/spring-projects/spring-flo.git#fdf3b6ffbc9bbf80eb3ad9a125d0f6241cbeb0fc",
40+
"spring-flo": "git://github.com/spring-projects/spring-flo.git#0dcd8726280d53239d7d32f4b3788d40b9a01ff8",
4141
"stompjs": "2.3.3",
4242
"tixif-ngx-busy": "0.0.5",
43-
"zone.js": "0.8.18"
43+
"zone.js": "0.8.18",
44+
"jshint": "2.9.5"
4445
},
4546
"devDependencies": {
4647
"@angular/cli": "1.3.0",

ui/src/app/shared/flo/flo.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,11 @@ table.zoom-canvas-control {
419419
position: absolute;
420420
}
421421

422+
.code-editor-host {
423+
height: 120px;
424+
width: 405px;
425+
border: 1px solid;
426+
border-color: $btn-default-border;
427+
}
428+
429+

ui/src/app/shared/flo/support/app-metadata.ts

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Flo } from 'spring-flo';
22
import { DetailedAppRegistration, ConfigurationMetadataProperty } from '../../model/detailed-app-registration.model';
33
import { Observable} from 'rxjs/Observable';
4-
4+
import { Utils } from './utils';
55

66
/**
77
* Class containing metadata for a stream application.
@@ -13,7 +13,7 @@ export class AppMetadata implements Flo.ElementMetadata {
1313

1414
private _dataPromise: Promise<DetailedAppRegistration>;
1515

16-
private _propertiesPromise: Promise<Map<string, Flo.PropertyMetadata>>;
16+
private _propertiesPromise: Promise<Map<string, AppPropertyMetadata>>;
1717

1818
constructor(
1919
private _group: string,
@@ -29,19 +29,33 @@ export class AppMetadata implements Flo.ElementMetadata {
2929
return this._dataPromise;
3030
}
3131

32-
get propertiesPromise(): Promise<Map<string, Flo.PropertyMetadata>> {
32+
get propertiesPromise(): Promise<Map<string, AppPropertyMetadata>> {
3333
if (!this._propertiesPromise) {
3434
this._propertiesPromise = new Promise(resolve => this.dataPromise.then((data: DetailedAppRegistration) => {
35-
const properties = new Map<string, Flo.PropertyMetadata>();
35+
const properties = new Map<string, AppPropertyMetadata>();
3636
if (data) {
3737
data.options.map((o: ConfigurationMetadataProperty) => {
38-
const propertyMetadata: Flo.PropertyMetadata = {
39-
id: o.id,
40-
name: o.name,
41-
description: o.description || o.shortDescription,
42-
defaultValue: o.defaultValue,
43-
type: o.type
44-
};
38+
const propertyMetadata: AppPropertyMetadata = new AppPropertyMetadata(o);
39+
if (o.sourceType === Utils.SCRIPTABLE_TRANSFORM_SOURCE_TYPE) {
40+
switch (o.name.toLowerCase()) {
41+
case 'language':
42+
propertyMetadata.options = [
43+
undefined, 'groovy', 'javascript', 'ruby', 'python'
44+
];
45+
break;
46+
case 'script':
47+
propertyMetadata.code = {
48+
langPropertyName: 'scriptable-transformer.language'
49+
};
50+
break;
51+
}
52+
} else if (o.sourceType === Utils.RX_JAVA_PROCESSOR_SOURCE_TYPE) {
53+
if (o.name.toLowerCase() === 'code') {
54+
propertyMetadata.code = {
55+
language: 'java'
56+
};
57+
}
58+
}
4559
if (o.type) {
4660
switch (o.type) {
4761
case 'java.util.concurrent.TimeUnit':
@@ -77,11 +91,11 @@ export class AppMetadata implements Flo.ElementMetadata {
7791
return Promise.resolve('');
7892
}
7993

80-
get(property: string): Promise<Flo.PropertyMetadata> {
94+
get(property: string): Promise<AppPropertyMetadata> {
8195
return this.propertiesPromise.then(properties => properties.get(property));
8296
}
8397

84-
properties(): Promise<Map<string, Flo.PropertyMetadata>> {
98+
properties(): Promise<Map<string, AppPropertyMetadata>> {
8599
return this.propertiesPromise;
86100
}
87101

@@ -90,3 +104,42 @@ export class AppMetadata implements Flo.ElementMetadata {
90104
}
91105

92106
}
107+
108+
export interface CodeOptions {
109+
readonly language?: string;
110+
readonly langPropertyName?: string;
111+
}
112+
113+
export class AppPropertyMetadata implements Flo.PropertyMetadata {
114+
115+
public options: string[];
116+
117+
public code: CodeOptions;
118+
119+
constructor(private metadata: ConfigurationMetadataProperty) {}
120+
121+
get id(): string {
122+
return this.metadata.id;
123+
}
124+
125+
get name(): string {
126+
return this.metadata.name;
127+
}
128+
129+
get description(): string {
130+
return this.metadata.description || this.metadata.shortDescription;
131+
}
132+
133+
get defaultValue() {
134+
return this.metadata.defaultValue;
135+
}
136+
137+
get type(): string {
138+
return this.metadata.type;
139+
}
140+
141+
get sourceType(): string {
142+
return this.metadata.sourceType;
143+
}
144+
145+
}

ui/src/app/shared/flo/support/properties-group-model.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Flo, Properties } from 'spring-flo';
22
import { Validators } from '@angular/forms';
33
import { dia } from 'jointjs';
4+
import { Utils } from './utils';
45

56
/**
67
* Utility class for working with Properties.
@@ -31,11 +32,19 @@ export class PropertiesGroupModel extends Properties.PropertiesGroupModel {
3132
inputType = Properties.InputType.CHECKBOX;
3233
break;
3334
default:
34-
if (Array.isArray(property.metadata.options)) {
35+
if (property.metadata.code) {
36+
if (property.metadata.code.langPropertyName) {
37+
return new Properties.CodeControlModelWithDynamicLanguageProperty(property,
38+
property.metadata.code.langPropertyName, this, Utils.encodeTextToDSL, Utils.decodeTextFromDSL);
39+
} else {
40+
return new Properties.GenericCodeControlModel(property, property.metadata.code.language,
41+
Utils.encodeTextToDSL, Utils.decodeTextFromDSL);
42+
}
43+
} else if (Array.isArray(property.metadata.options)) {
3544
return new Properties.SelectControlModel(property,
3645
Properties.InputType.SELECT, (<Array<string>> property.metadata.options).map(o => {
3746
return {
38-
name: o.charAt(0).toUpperCase() + o.substr(1).toLowerCase(),
47+
name: o ? o.charAt(0).toUpperCase() + o.substr(1).toLowerCase() : '< SELECT >',
3948
value: o === property.defaultValue ? undefined : o
4049
};
4150
}));
@@ -73,7 +82,7 @@ export class PropertiesGroupModel extends Properties.PropertiesGroupModel {
7382
}
7483
const valueFromName = this.cell.attr(nameAttr);
7584
const valueFromId = this.cell.attr(idAttr);
76-
if (valueFromName === undefined || valueFromName === null && !(valueFromId === undefined || valueFromId === null)) {
85+
if ((valueFromName === undefined || valueFromName === null) && !(valueFromId === undefined || valueFromId === null)) {
7786
return idAttr;
7887
} else {
7988
return nameAttr;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
import { Utils } from './utils';
3+
4+
describe('utils', () => {
5+
6+
it('encode string with no line breaks', () => {
7+
expect(Utils.encodeTextToDSL('hoho')).toEqual('"hoho"');
8+
});
9+
10+
it('encode string with line breaks', () => {
11+
expect(Utils.encodeTextToDSL('hoho\nkoko\n')).toEqual('"hoho\\nkoko\\n"');
12+
});
13+
14+
it('encode string with quotes', () => {
15+
expect(Utils.encodeTextToDSL('hoho "koko"')).toEqual('"hoho ""koko"""');
16+
});
17+
18+
it('decode string with no line breaks', () => {
19+
expect(Utils.decodeTextFromDSL('"hoho"')).toEqual('hoho');
20+
});
21+
22+
it('decode string with line breaks', () => {
23+
expect(Utils.decodeTextFromDSL('"hoho\\nkoko\\n"')).toEqual('hoho\nkoko\n');
24+
});
25+
26+
it('encode string with quotes', () => {
27+
expect(Utils.decodeTextFromDSL('"hoho ""koko"""')).toEqual('hoho "koko"');
28+
});
29+
30+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2015-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Flo } from 'spring-flo';
18+
19+
/**
20+
* Utilities for Flo based graph editors.
21+
*
22+
* @author Alex Boyko
23+
*/
24+
export class Utils {
25+
26+
static RX_JAVA_PROCESSOR_SOURCE_TYPE = 'org.springframework.cloud.stream.app.transform.ProgrammableRxJavaProcessorProperties';
27+
static SCRIPTABLE_TRANSFORM_SOURCE_TYPE =
28+
'org.springframework.cloud.stream.app.scriptable.transform.processor.ScriptableTransformProcessorProperties';
29+
30+
static RX_JAVA_PROCESSOR_NAME = 'rx-java-processor';
31+
static SCRIPTABLE_TRANSFORM_NAME = 'scriptable-transform';
32+
33+
static encodeTextToDSL(text: string): string {
34+
return '\"' + text.replace(/(?:\r\n|\r|\n)/g, '\\n').replace(/"/g, '""') + '\"';
35+
}
36+
37+
static decodeTextFromDSL(dsl: string): string {
38+
if (dsl.charAt(0) === '\"' && dsl.charAt(dsl.length - 1) === '\"') {
39+
dsl = dsl.substr(1, dsl.length - 2);
40+
}
41+
return dsl.replace(/\\n/g, '\n').replace(/\"\"/g, '"');
42+
}
43+
44+
static isCodeTypeProperty(metadata: Flo.ElementMetadata, property: string): boolean {
45+
const propertyLowerCase = property.toLowerCase();
46+
return (metadata.name === Utils.RX_JAVA_PROCESSOR_NAME
47+
&& (propertyLowerCase === 'code' || propertyLowerCase === 'rxjava-processor.code'))
48+
|| (metadata.name === Utils.SCRIPTABLE_TRANSFORM_NAME
49+
&& (propertyLowerCase === 'script' || propertyLowerCase === 'scriptable-transformer.script'));
50+
}
51+
52+
}

ui/src/app/shared/model/detailed-app-registration.model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class ConfigurationMetadataProperty implements Serializable<Configuration
3838
public shortDescription: string;
3939
public defaultValue: string;
4040
public deprecation: Deprecation;
41+
public sourceType: string;
4142
public isDeprecated: boolean;
4243

4344
/**
@@ -55,6 +56,7 @@ export class ConfigurationMetadataProperty implements Serializable<Configuration
5556
this.shortDescription = input.shortDescription ? input.shortDescription : undefined;
5657
this.defaultValue = input.defaultValue ? input.defaultValue : undefined;
5758
this.deprecation = input.deprecation ? new Deprecation().deserialize(input.deprecation) : undefined;
59+
this.sourceType = input.sourceType ? input.sourceType : undefined;
5860
this.isDeprecated = input.deprecated ? input.deprecated : false;
5961
return this;
6062
}

ui/src/app/streams/flo/metamodel.service.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { ApplicationType } from '../../shared/model/application-type';
2121
import { convertGraphToText } from './graph-to-text';
2222
import { convertTextToGraph } from './text-to-graph';
2323
import { OTHER_GROUP_TYPE } from './support/shapes';
24-
import { AppMetadata} from '../../shared/flo/support/app-metadata';
24+
import { AppMetadata } from '../../shared/flo/support/app-metadata';
2525

2626
/**
2727
* Metamodel Service for Flo based Stream Definition graph editor
@@ -67,20 +67,6 @@ export class MetamodelService implements Flo.Metamodel {
6767
}
6868
}
6969

70-
encodeTextToDSL(text: string): string {
71-
const retval = '\"' + text.replace(/(?:\r\n|\r|\n)/g, '\\n').replace(/"/g, '""') + '\"';
72-
return retval;
73-
}
74-
75-
decodeTextFromDSL(dsl: string): string {
76-
if (dsl.charAt(0) === '\"' && dsl.charAt(dsl.length - 1) === '\"') {
77-
dsl = dsl.substr(1, dsl.length - 2);
78-
}
79-
const retval = dsl.replace(/\\n/g, '\n').replace(/\"\"/g, '"');
80-
return retval;
81-
}
82-
83-
8470
groups(): Array<string> {
8571
return ['source', 'processor', 'sink', 'other'];
8672
}
@@ -102,7 +88,7 @@ export class MetamodelService implements Flo.Metamodel {
10288
}).forEach(item => {
10389

10490
if (!metamodel.has(item.type.toString())) {
105-
metamodel.set(item.type.toString(), new Map<string, Flo.ElementMetadata>());
91+
metamodel.set(item.type.toString(), new Map<string, AppMetadata>());
10692
}
10793
const group: Map<string, Flo.ElementMetadata> = metamodel.get(item.type.toString());
10894
if (group.has(item.name)) {
@@ -122,7 +108,7 @@ export class MetamodelService implements Flo.Metamodel {
122108
return this.request;
123109
}
124110

125-
private createEntry(type: ApplicationType, name: string, metadata?: Flo.ExtraMetadata): Flo.ElementMetadata {
111+
private createEntry(type: ApplicationType, name: string, metadata?: Flo.ExtraMetadata): AppMetadata {
126112
return new AppMetadata(
127113
type.toString(),
128114
name,

ui/src/app/streams/flo/node/node.component.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,23 @@
44

55
.tooltip-property-value {
66
word-break: break-all;
7+
max-width: 390px;
8+
white-space: pre;
9+
text-overflow: ellipsis;
10+
overflow: hidden;
11+
text-align: left;
712
}
813

914
.tooltip-property-key {
15+
text-align: left;
1016
vertical-align: top;
17+
max-width: 200px;
18+
vertical-align: top;
19+
text-overflow: ellipsis;
20+
overflow: hidden;
21+
}
22+
23+
.tooltip-property-value-code {
24+
font-family: monospace;
25+
font-size: 85%;
1126
}

ui/src/app/streams/flo/node/node.component.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Component, ViewEncapsulation } from '@angular/core';
22
import { dia } from 'jointjs';
33
import { Flo, Constants } from 'spring-flo';
44
import { ElementComponent } from '../../../shared/flo/support/shape-component';
5+
import { Utils } from '../../../shared/flo/support/utils';
56

67
/**
78
* Component for displaying application properties and capturing their values.
@@ -24,7 +25,14 @@ export class NodeComponent extends ElementComponent {
2425
}
2526

2627
getPropertyValue(property: string): any {
27-
return this.view ? this.view.model.attr(`props/${property}`) : '';
28+
if (this.view) {
29+
const value = this.view.model.attr(`props/${property}`);
30+
if (this.isCode(property)) {
31+
return Utils.decodeTextFromDSL(value);
32+
}
33+
return value;
34+
}
35+
return '';
2836
}
2937

3038
isCanvas(): boolean {
@@ -69,7 +77,7 @@ export class NodeComponent extends ElementComponent {
6977
}
7078

7179
isCode(property: string): boolean {
72-
return false;
80+
return Utils.isCodeTypeProperty(this.metadata, property);
7381
}
7482

7583
keys(o: any): Array<string> {

0 commit comments

Comments
 (0)