Skip to content

Commit ec4f816

Browse files
authored
Merge pull request #27 from Landoop/feature/connect-improvements
Feature/connect improvements
2 parents 4d7eef4 + 8c34f71 commit ec4f816

File tree

12 files changed

+239
-151
lines changed

12 files changed

+239
-151
lines changed

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ RUN wget "https://caddyserver.com/download/build?os=linux&arch=amd64&features="
1313
&& rm -f /caddy.tgz
1414

1515
# Add and Setup Kafka-Connect-Ui
16-
ARG CONNECT_UI_URL=https://github.com/Landoop/kafka-connect-ui/releases/download/v.0.9.0/kafka-connect-ui-0.9.0.tar.gz
16+
ARG CONNECT_UI_URL=https://github.com/Landoop/kafka-connect-ui/releases/download/v.0.9.1/kafka-connect-ui-0.9.1.tar.gz
1717
RUN wget "${CONNECT_UI_URL}" -O /kafka-connect-ui.tar.gz \
1818
&& mkdir /kafka-connect-ui \
1919
&& tar xzf /kafka-connect-ui.tar.gz -C /kafka-connect-ui \

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ <h5><a href="/#/" style="color:#fff;font-weight: normal;font-size: 14px;">KAFKA
2525
</div>
2626
<label ng-show="!missingEnvJS && clusters.length > 1 && !isHome" style="color:#ccc; font-size:12px"><b>SELECT CLUSTER :</b></label>
2727
<md-input-container ng-show="!missingEnvJS && clusters.length > 1 && !isHome" class="selectCluster">
28-
<md-select ng-model="connectEndPoint">
28+
<md-select ng-model="connectEndPoint" aria-label="select cluster">
2929
<md-option ng-repeat="connectEndPoint in clusters track by $index"
3030
ng-click="updateEndPoint(connectEndPoint.NAME)"
3131
value="{{connectEndPoint.NAME}}" ng-selected="{{cluster.NAME == connectEndPoint.NAME}}"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "kafka-connect-ui",
3-
"version": "0.9.0",
3+
"version": "0.9.1",
44
"description": "A user interface for managing Kafka Connectors",
55
"readme": "README.md",
66
"main": "Gruntfile.js",

src/assets/css/styles.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ header {
1515
text-decoration: none;
1616
}
1717

18+
md-card {
19+
box-shadow:none;
20+
}
21+
1822
header h5 {
1923
margin:0px;
2024
}
@@ -103,7 +107,7 @@ header h5 a {
103107
magin-top: -20px;
104108
min-height: 30px;
105109
font-size: 14px;
106-
border-bottom: 1px solid rgba(0,0,0,0.12);
110+
/* border-bottom: 1px solid rgba(0,0,0,0.12); */
107111
}
108112

109113
md-chips.md-default-theme .md-chips, md-chips .md-chips {

src/kafka-connect/config/config.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<md-content flex layout-padding>
33
<b>Kafka Connect :</b> {{kafkaConnectURL}} <br>
44
<span ng-show="showVersion"> <b>Kafka Connect Version :</b> {{version}} <br></span>
5-
<span> <b>Kafka Connect UI Version :</b> 0.9.0 <br></span>
5+
<span> <b>Kafka Connect UI Version :</b> 0.9.1 <br></span>
66
<span ng-show="connectionFailure" class="red">{{connectivityError}}</span><br>
77
</md-content>
88
</md-card>

src/kafka-connect/create-connector/create-connector.controller.js

Lines changed: 132 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
$scope.connector in this controller is the connector object from supported connectors.
33
Config is created on the fly using the `template` models.
44
*/
5-
angularAPP.controller('CreateConnectorCtrl', function ($scope, $rootScope, $http, $log, $routeParams, $location, $filter, KafkaConnectFactory, supportedConnectorsFactory, NewConnectorFactory, env, constants) {
5+
angularAPP.controller('CreateConnectorCtrl', function ($scope, $rootScope, $http, $log, $routeParams, $location, $filter, KafkaConnectFactory, supportedConnectorsFactory, NewConnectorFactory, env, constants, $q) {
66
KafkaConnectFactory.getConnectorPlugins().then(function(allPlugins) {
77
var className;
88

@@ -31,118 +31,171 @@ angularAPP.controller('CreateConnectorCtrl', function ($scope, $rootScope, $http
3131
$scope.isDisabledTab = function(index) { return (index == $scope.selectedTabIndex) ? 'false' : 'true'; }
3232

3333

34+
$scope.aceLoaded = function (_editor) {
35+
console.log("Ace for create-connector loaded");
36+
$scope.editor = _editor;
37+
$scope.editor.$blockScrolling = Infinity;
38+
$scope.acePropertyFileSession = _editor.getSession();
39+
var lines = 15;//$scope.connectorDetails.connectorDetailsInString.split("\n").length;
40+
_editor.setOptions({
41+
minLines: lines,
42+
maxLines: lines,
43+
highlightActiveLine: false
44+
});
45+
};
46+
3447

3548
//If user changes config from the editor
3649
$scope.$watch('formValuesPerSection', function() {
3750
if ($scope.formValuesPerSection) {
38-
console.log('test', $scope.formValuesPerSection)
51+
//console.log('test', $scope.formValuesPerSection)
3952
$scope.formValuesPerSection = $scope.formValuesPerSection.replace("\r", "");
40-
console.log('test', $scope.formValuesPerSection)
53+
//console.log('test', $scope.formValuesPerSection)
4154
var flatValuesArray = $scope.formValuesPerSection.split("\n");
42-
$scope.curlCommand = NewConnectorFactory.getCurlCommand(flatValuesArray);
55+
validateConnectorFn();
4356
}
4457
});
4558

4659

47-
//TODO save & Validate = duplicate code
48-
49-
$scope.validateConnector = function (object) {
50-
51-
flatValuesArray = $scope.formValuesPerSection.split('\n');
60+
function validateConnectorFn () {
61+
var deferred = $q.defer();
5262
var connectorCurlObject = {
53-
name: "",
54-
config: {}
55-
};
56-
angular.forEach(flatValuesArray, function (propertyLine) {
57-
if (propertyLine.length > 2) {
58-
var key = propertyLine.substring(0, propertyLine.indexOf('='));
59-
var value = propertyLine.substring(propertyLine.indexOf('=') + 1);
60-
connectorCurlObject.config["" + key] = value;
61-
}
62-
});
63+
name: "",
64+
config: {}
65+
};
66+
var errorConfigs = [];
6367

68+
flatValuesArray = $scope.formValuesPerSection.split('\n');
6469
config = NewConnectorFactory.getJSONConfigFlat(flatValuesArray);
65-
var classname = $scope.connector.class;
70+
71+
// Make sure the 'classname' is a valid one - as it can crash the connect services
72+
var classname = flatValuesArray.find(function (p) {
73+
return (p.indexOf("connector.class=") == 0)
74+
}).split('connector.class=').join('');
75+
if (classname != $scope.connector.class) {
76+
console.log("error in classname -> " + classname);
77+
var errors = { errors : [ 'Classname "' + $scope.connector.class + '" is not defined' ] };
78+
errorConfigs.push(errors);
79+
}
80+
81+
//console.log("Error configs -> " + errorConfigs);
82+
//console.log(errorConfigs.length == 0);
83+
84+
if(errorConfigs == 0) {
85+
$scope.validConfig = constants.VIEW_MESSAGE_CONNECTOR_VALID;
86+
$scope.curlCommand = NewConnectorFactory.getCurlCommand(flatValuesArray);
87+
}
88+
$scope.errorConfigs = errorConfigs;
89+
6690
//STEP 1: Validate
6791
var validateConfigPromise = KafkaConnectFactory.validateConnectorConfig(classname, config);
6892
validateConfigPromise.then(
6993
function success(data) {
70-
$log.info('Total validation errors => ' + data.error_count);
94+
$log.info('Total validation errors from API => ' + data.error_count);
7195
//STEP 2: Get errors if any
72-
var errorConfigs = [];
73-
$scope.validConfig = ''
96+
$scope.validConfig = '';
97+
var validConnectorConfigKeys = [];
98+
var requiredConfigKeys = [];
7499
angular.forEach(data.configs, function (config) {
100+
//console.log("c-> " + config.value.name);
101+
//console.log(config);
75102
if (config.value.errors.length > 0) {
76103
errorConfigs.push(config.value);
77104
$log.info(config.value.name + ' : ' + config.value.errors[0]);
78105
}
106+
//console.log("config.value -> ");
107+
if ( (config.definition.required == true) || (config.value.name.startsWith("topic")) ){
108+
requiredConfigKeys.push(config.value.name);
109+
}
110+
console.log("Required/compulsory config keys: " + requiredConfigKeys);
111+
validConnectorConfigKeys.push(config.value.name);
112+
});
113+
//console.log("validConnectorConfigKeys -> " + validConnectorConfigKeys);
114+
angular.forEach(flatValuesArray, function (propertyLine) {
115+
if (propertyLine.length > 0) {
116+
if ( (propertyLine.indexOf("=") == -1) | (propertyLine.length < 3) ) {
117+
var errors = { errors : [ 'Line "' + propertyLine + '" is not a valid property line' ] };
118+
errorConfigs.push(errors);
119+
} else {
120+
var key = propertyLine.substring(0, propertyLine.indexOf('='));
121+
var value = propertyLine.substring(propertyLine.indexOf('=') + 1);
122+
if (validConnectorConfigKeys.indexOf( key.toLowerCase() ) == -1) {
123+
var errors = { errors : [ 'Config "' + key + '" is not supported' ] };
124+
errorConfigs.push(errors);
125+
} else
126+
if (value.length == 0) {
127+
var errors = { errors : [ 'Config "' + key + '" requires a value' ] };
128+
errorConfigs.push(errors);
129+
} else {
130+
connectorCurlObject.config["" + key] = value;
131+
}
132+
}
133+
}
134+
});
135+
// Now check the other way around. Whether a required property is not set
136+
angular.forEach(requiredConfigKeys, function (requiredKey) {
137+
var x = flatValuesArray.find(function(p) {
138+
var result = (p.indexOf(requiredKey) == 0);
139+
console.log(result + " " + p);
140+
return result
141+
});
142+
//console.log("x " + requiredKey + " " + x)
143+
if (x == undefined) {
144+
var errors = { errors : [ 'Required config "' + requiredKey + '" is not there' ] };
145+
errorConfigs.push(errors);
146+
};
79147
});
148+
80149
if(errorConfigs == 0) {
81150
$scope.validConfig = constants.VIEW_MESSAGE_CONNECTOR_VALID;
151+
$scope.curlCommand = NewConnectorFactory.getCurlCommand(flatValuesArray);
152+
deferred.resolve(constants.VIEW_MESSAGE_CONNECTOR_VALID);
153+
} else {
154+
deferred.reject(errorConfigs);
82155
}
83-
84156
$scope.errorConfigs = errorConfigs;
85157

86-
}, function (data, reason) {
158+
/* debug
159+
var flatKeysUsed = [];
160+
angular.forEach(flatValuesArray, function (propertyLine) {
161+
flatKeysUsed.push(propertyLine.split("=" , 1) + "");
162+
});
163+
console.log(validConnectorConfigKeys);
164+
console.log(flatKeysUsed);
165+
console.log(errorConfigs);
166+
*/
167+
},
168+
function error(data, reason) {
87169
$log.error('Failure : ' + data);
170+
deferred.reject(data);
88171
});
172+
return deferred.promise;
89173
}
90174

175+
$scope.validateConnector = function () {
176+
validateConnectorFn();
177+
}
178+
91179

92180
$scope.validateAndCreateConnector = function () {
93-
flatValuesArray = $scope.formValuesPerSection.split('\n');
94-
var connectorCurlObject = {
95-
name: "",
96-
config: {}
97-
};
98-
angular.forEach(flatValuesArray, function (propertyLine) {
99-
if (propertyLine.length > 2) {
100-
var key = propertyLine.substring(0, propertyLine.indexOf('='));
101-
var value = propertyLine.substring(propertyLine.indexOf('=') + 1);
102-
connectorCurlObject.config["" + key] = value;
103-
}
104-
});
105-
106-
config = NewConnectorFactory.getJSONConfigFlat(flatValuesArray);
107-
var classname = $scope.connector.class;
108-
109-
//STEP 1: Validate
110-
var validateConfigPromise = KafkaConnectFactory.validateConnectorConfig(classname, config);
111-
112-
113-
validateConfigPromise.then(
114-
function success(data) {
115-
$log.info('Total validation errors => ' + data.error_count);
116-
117-
//STEP 2: Get errors if any
118-
var errorConfigs = [];
119-
angular.forEach(data.configs, function (config) {
120-
if (config.value.errors.length > 0) {
121-
errorConfigs.push(config.value);
122-
$log.info(config.value.name + ' : ' + config.value.errors[0]);
123-
}
124-
});
125-
126-
//STEP 3: If no errors, create the connector
127-
if(errorConfigs.length == 0) {
128-
var config2 = NewConnectorFactory.getJSONConfig(flatValuesArray);
129-
KafkaConnectFactory.postNewConnector(config2).then(
130-
function successCallback(response) {
131-
console.log("POSTING " + JSON.stringify(response));
132-
$location.path("#/connector/" + response.name); //TODO location doesn't work, move to controller
133-
$rootScope.newConnectorChanges = true;
134-
135-
136-
});
137-
} else {
138-
$scope.errorConfigs = errorConfigs;
139-
}
140181

182+
validateConnectorFn().then(
183+
function success(data) {
184+
console.log("I will now post the connector");
185+
KafkaConnectFactory.postNewConnector(NewConnectorFactory.getJSONConfig(flatValuesArray)).then(
186+
function successCallback(response) {
187+
console.log("POSTING " + JSON.stringify(response));
188+
$location.path("#/connector/" + response.name); //TODO location doesn't work, move to controller
189+
$rootScope.newConnectorChanges = true;
190+
});
141191
}, function (data, reason) {
142-
$log.error('Failure : ' + data);
143-
});
192+
$scope.validConfig = "Please fix the below issues";
193+
console.log("I can NOT post the connector - as validation errors exist");
194+
});
195+
144196
}
145197

198+
146199
$scope.querySearch = function(query){
147200
return $http.get(env.KAFKA_REST() + '/topics')
148201
.then(function(response){
@@ -155,9 +208,11 @@ angularAPP.controller('CreateConnectorCtrl', function ($scope, $rootScope, $http
155208
var type="Unknown";
156209
var a = pluginClass.split('.');
157210
if (a[a.length-1].toLowerCase().indexOf('sink') > 0) {
158-
type="Sink"
211+
type="Sink";
212+
var myElements = [{key:'name',value: a[a.length-1], required: true}, {key:'connector.class', value: pluginClass, required: true},{key:'topics',value: 'TopicName_'+ a[a.length-1], required: true}, {key:'tasks.max',value: 1, required: true}];
159213
} else if (a[a.length-1].toLowerCase().indexOf('source') > 0) {
160-
type="Source"
214+
type="Source";
215+
var myElements = [{key:'name',value: a[a.length-1], required: true}, {key:'connector.class', value: pluginClass, required: true}, {key:'tasks.max',value: 1, required: true}];
161216
}
162217

163218
var connector = {
@@ -172,7 +227,7 @@ angularAPP.controller('CreateConnectorCtrl', function ($scope, $rootScope, $http
172227
id : "step1",
173228
sections : [
174229
{
175-
elements : [{key:'name',value: a[a.length-1], required: true}, {key:'connector.class', value: pluginClass, required: true},{key:'topics',value: 'TopicName_'+ a[a.length-1], required: true}, {key:'tasks.max',value: 1, required: true}]
230+
elements : myElements
176231
}
177232
]
178233
}

src/kafka-connect/create-connector/create-connector.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ <h3 style="font-size:12px;padding:0px; margin:0px">{{connector.name}}</h3>
5151
ui-ace="{
5252
useWrapMode: true,
5353
mode: 'properties',
54-
firstLineNumber: 1
54+
showPrintMargin: false,
55+
firstLineNumber: 1,
56+
blockScrolling: Infinity,
57+
onLoad: aceLoaded
5558
}"></div>
5659
<!--Show Curl command-->
5760
<div id="curlCommand" ng-if="showCurl"
@@ -71,11 +74,8 @@ <h3 style="font-size:12px;padding:0px; margin:0px">{{connector.name}}</h3>
7174
<md-button ng-hide="connector.isUndefined || toggleEditor " ng-disabled="forms.cForm.$invalid" ng-click="previousTab()">
7275
<i class="fa fa-angle-double-left" aria-hidden="true"></i> Back
7376
</md-button>
74-
<md-button ng-click="validateConnector(formValuesPerSection)">
75-
Validate
76-
</md-button>
77-
<md-button ng-disabled="forms.cForm.$invalid" ng-click="validateAndCreateConnector()">
78-
Validate and Create
77+
<md-button ng-disabled="errorConfigs.length != 0" ng-click="validateAndCreateConnector()">
78+
Create
7979
</md-button>
8080
</md-card-actions>
8181

src/kafka-connect/export-configs/export-configs.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ <h2 flex style="font-weight:300; padding-left:20px; margin-bottom:10px">Export C
2626
ng-readonly="true"
2727
ng-style="{'background-color':aceBackgroundColor }"
2828
ng-model="propertiesStr"
29-
ui-ace="{ mode: 'properties', firstLineNumber: 1, onLoad: aceLoaded, onChange: aceChanged }"
29+
ui-ace="{ mode: 'properties', firstLineNumber: 1, onLoad: aceLoaded, onChange: aceChanged, blockScrolling: Infinity }"
3030
valid-json>
3131
</div>
3232
</md-content>
@@ -39,7 +39,7 @@ <h2 flex style="font-weight:300; padding-left:20px; margin-bottom:10px">Export C
3939
ng-readonly="true"
4040
ng-style="{'background-color':aceBackgroundColor }"
4141
ng-model="jsons"
42-
ui-ace="{ mode: 'batchfile', firstLineNumber: 1, onLoad: aceLoaded, onChange: aceChanged }"
42+
ui-ace="{ mode: 'batchfile', firstLineNumber: 1, onLoad: aceLoaded, onChange: aceChanged, blockScrolling: Infinity }"
4343
valid-json>
4444
</div>
4545
</md-content>
@@ -51,7 +51,7 @@ <h2 flex style="font-weight:300; padding-left:20px; margin-bottom:10px">Export C
5151
ng-readonly="true"
5252
ng-style="{'background-color':aceBackgroundColor }"
5353
ng-model="curlsStr"
54-
ui-ace="{ mode: 'batchfile', firstLineNumber: 1, onLoad: aceLoaded, onChange: aceChanged }"
54+
ui-ace="{ mode: 'batchfile', firstLineNumber: 1, onLoad: aceLoaded, onChange: aceChanged, blockScrolling: Infinity }"
5555
valid-json>
5656
</div>
5757
</md-content>

src/kafka-connect/home/home.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ <h3>
1111
Configured Clusters
1212
</h3>
1313
<span flex></span>
14-
<md-button ng-click="loadData()"><i class="fa fa-refresh" aria-hidden="true"></i></md-button>
14+
<md-button aria-label="Refresh status" ng-click="loadData()"><i class="fa fa-refresh" aria-hidden="true"></i></md-button>
1515
</div>
1616
</md-toolbar>
1717

0 commit comments

Comments
 (0)