http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/html/process/processFormTpl.html ---------------------------------------------------------------------- diff --git a/falcon-ui/app/html/process/processFormTpl.html b/falcon-ui/app/html/process/processFormTpl.html index 7bf423e..00d2c66 100644 --- a/falcon-ui/app/html/process/processFormTpl.html +++ b/falcon-ui/app/html/process/processFormTpl.html @@ -17,79 +17,90 @@ * limitations under the License. */ --> -<div class="col-sm-24 entityForm"> - <div class="col-sm-22 col-sm-offset-2"> +<div class="col-xs-22 col-xs-offset-1 entityForm" id="processFormTmpl"> + <div class="col-xs-24"> <div class="row"> - <h3 id="formTitle" class="col-sm-24"> - New Process + + <h3 id="formTitle" class="col-xs-24"> + <span class="entypo cycle icon-lg"></span> New Process </h3> - <div class="col-sm-15 detailsBox"> - <div class="processProgressBox" ng-class="{ - general:isActive('forms.process.general'), - properties:isActive('forms.process.properties'), - clusters:isActive('forms.process.clusters'), - inputsAndOutputs: isActive('forms.process.io'), - summary:isActive('forms.process.summary') - }"> - <div class="progressBar col-md-24"> - <div> - <span> - <div class="fir">1<span class="entypo check"></span></div> - <h6>General</h6> - </span> - <span> - <div class="sec">2<span class="entypo check"></span></div> - <h6>Properties</h6> - </span> - <span> - <div class="thi">3<span class="entypo check"></span></div> - <h6>Clusters</h6> - </span> - <span> - <div class="fou">4<span class="entypo check"></span></div> - <h6>Inputs & Outputs</h6> - </span> - <span> - <div class="fif">5<span class="entypo check"></span></div> - <h6>Summary</h6> - </span> + <div ng-class="{'col-xs-12' : propsOpen, 'col-xs-20' : !propsOpen}"> + <div class="detailsBox"> + <div class="processProgressBox" ng-class="{ + general:isActive('forms.process.general'), + properties:isActive('forms.process.properties'), + clusters:isActive('forms.process.clusters'), + inputsAndOutputs: isActive('forms.process.io'), + summary:isActive('forms.process.summary') + }"> + <div class="progressBar col-xs-24"> + <div> + <span> + <div class="fir">1<span class="entypo check"></span></div> + <h6>General</h6> + </span> + <span> + <div class="sec">2<span class="entypo check"></span></div> + <h6>Properties</h6> + </span> + <span> + <div class="thi">3<span class="entypo check"></span></div> + <h6>Clusters</h6> + </span> + <span> + <div class="fou">4<span class="entypo check"></span></div> + <h6>Inputs & Outputs</h6> + </span> + <span> + <div class="fif">5<span class="entypo check"></span></div> + <h6>Summary</h6> + </span> + </div> </div> </div> - </div> - - <div class="row"> - <div class="col-sm-offset-1 col-sm-22"> - <fieldset id="fieldWrapper" ng-disabled="!editXmlDisabled"> - <div ui-view class="formViewContainer"></div> - </fieldset> + + <div class="row"> + <div class="col-xs-offset-1 col-xs-22"> + <fieldset id="fieldWrapper" ng-disabled="!editXmlDisabled"> + <div ui-view class="formViewContainer"></div> + </fieldset> + </div> </div> </div> - </div> - <div class="col-sm-8 detailsBox col-sm-offset-1"> - <div class="row"> + <div ng-class="{'col-xs-12' : propsOpen, 'col-xs-4' : !propsOpen}"> + <div class="detailsBox"> + <div class="row"> - <h5 class="col-xs-13 col-xs-offset-1 noSpecial">XML Preview</h5> - <div class="col-xs-9"> - <div id="editXmlButton" class="btn btn-default btn-xs pull-right" ng-click="toggleEditXml()" ng-class="{'btn-warning':!editXmlDisabled}"> - Edit XML + <div class="col-xs-13 col-xs-offset-1 noSpecial"> + <h5><i class="pointer glyphicon" ng-click="propsOpen = !propsOpen" ng-class="propsOpen ? 'glyphicon-minus-sign':'glyphicon-plus-sign'"></i> XML Preview</h5> + </div> + + <div ng-if="propsOpen" class="col-xs-9"> + <button type="button" + id="editXmlButton" + class="btn btn-default btn-xs pull-right" + ng-click="toggleEditXml()" + ng-class="{'btn-warning':!editXmlDisabled}"> + <div ng-if="editXmlDisabled">Edit XML</div> + <div ng-if="!editXmlDisabled">Finish</div> + </button> </div> - </div> - <div class="col-sm-24"> - <div class="row"> - <div class="col-sm-22 col-sm-offset-1"> - <textarea ng-model="prettyXml" rows="35" class="form-control" ng-disabled="editXmlDisabled"> - </textarea> + <div ng-show="propsOpen" class="col-xs-24"> + <div class="row"> + <div class="col-xs-22 col-xs-offset-1" > + <textarea ng-model="prettyXml" class="form-control prettyXml" elastic ng-disabled="editXmlDisabled"></textarea> + </div> </div> </div> + </div> - </div> </div> - + </div> </div> </div>
http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/html/process/processSummary.html ---------------------------------------------------------------------- diff --git a/falcon-ui/app/html/process/processSummary.html b/falcon-ui/app/html/process/processSummary.html new file mode 100644 index 0000000..e9eb4a4 --- /dev/null +++ b/falcon-ui/app/html/process/processSummary.html @@ -0,0 +1,184 @@ +<!-- +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<div class="summaryBox" id="processFormSummary"> + <div class="row"> + <h5 class="col-sm-24">{{entityTypeLabel}}</h5> + + <label class="col-sm-24">Name</label> + <label class="col-sm-24 light">{{process.name}}</label> + + <label class="col-sm-24">Tags</label> + + <div class="col-sm-24"> + <div ng-repeat="tag in process.tags | filter:{key: '!!'}"> + {{tag.key}} = {{tag.value}} + </div> + <div ng-show="!hasTags()">No tags selected</div> + </div> + + <h5 class="col-sm-24">Access Control List</h5> + + <div class="row"> + <div class="col-sm-8"> + <label class="col-sm-24">Owner</label> + <label class="col-sm-24 light">{{process.ACL.owner}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Group</label> + <label class="col-sm-24 light">{{process.ACL.group}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Permissions</label> + <label class="col-sm-24 light">{{process.ACL.permission}}</label> + </div> + </div> + + <h5 class="col-sm-24">Workflow</h5> + + <div class="row"> + <div class="col-sm-8"> + <label class="col-sm-24">Name</label> + <label class="col-sm-24 light">{{process.workflow.name}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Engine</label> + <label class="col-sm-24 light">{{process.workflow.engine}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Version</label> + <label class="col-sm-24 light">{{process.workflow.version}}</label> + </div> + </div> + <label class="col-sm-24">Path</label> + <label class="col-sm-24 light">{{process.workflow.path}}</label> + + + <h5 class="col-sm-24">Timing</h5> + <label class="col-sm-24" ng-if="process.timezone">Timezone</label> + <label class="col-sm-24 light">{{process.timezone}}</label> + + <div class="row"> + <div class="col-sm-8"> + <label class="col-sm-24">Frequency</label> + <label class="col-sm-24 light">Every {{process.frequency.quantity}} {{process.frequency.unit}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Max. parallel instances</label> + <label class="col-sm-24 light">{{process.parallel}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Order</label> + <label class="col-sm-24 light">{{process.order}}</label> + </div> + </div> + + <h5 class="col-sm-24">Retry</h5> + + <div class="row"> + <div class="col-sm-8"> + <label class="col-sm-24">Policy</label> + <label class="col-sm-24 light">{{process.retry.policy}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Attempts</label> + <label class="col-sm-24 light">{{process.retry.attempts}}</label> + </div> + <div class="col-sm-8"> + <label class="col-sm-24">Delay</label> + <label class="col-sm-24 light">Up to {{process.retry.delay.quantity}} {{process.retry.delay.unit}}</label> + </div> + </div> + + + </div> +</div> + +<div class="summaryBox"> + <div class="row"> + <h5 class="col-sm-24">Clusters</h5> + + <div ng-repeat="cluster in process.clusters"> + <div class="row col-sm-offset-1 col-sm-22 detailsBox"> + <label class="col-sm-24">Name</label> + <label class="col-sm-24 light">{{cluster.name}}</label> + + <h5 class="col-sm-24">Validity</h5> + + <div class="row"> + <div class="col-sm-12"> + <label class="col-sm-24">Start</label> + <label class="col-sm-24 light">{{dateFormatter(entity.start)}} Z</label> + </div> + <div class="col-sm-12"> + <label class="col-sm-24">End</label> + <label class="col-sm-24 light">{{dateFormatter(entity.end)}} Z</label> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="summaryBox"> + <div class="row"> + <h5 class="col-sm-24">Inputs</h5> + + <div ng-repeat="input in process.inputs"> + <div class="row col-sm-offset-1 col-sm-22 detailsBox"> + <label class="col-sm-24">Name</label> + <label class="col-sm-24 light">{{input.name}}</label> + <label class="col-sm-24">Feed</label> + <label class="col-sm-24 light">{{input.feed}}</label> + + <h5 class="col-sm-24">Instance</h5> + + <div class="row"> + <div class="col-sm-12"> + <label class="col-sm-24">Start</label> + <label class="col-sm-24 light">{{input.start}}</label> + </div> + <div class="col-sm-12"> + <label class="col-sm-24">End</label> + <label class="col-sm-24 light">{{input.end}}</label> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="summaryBox"> + <div class="row"> + <h5 class="col-sm-24">Outputs</h5> + + <div ng-repeat="output in process.outputs"> + <div class="row col-sm-offset-1 col-sm-22 detailsBox"> + <label class="col-sm-24">Name</label> + <label class="col-sm-24 light">{{output.name}}</label> + <label class="col-sm-24">Feed</label> + <label class="col-sm-24 light">{{output.feed}}</label> + + <h5 class="col-sm-24">Instance</h5> + <label class="col-sm-24">Instance</label> + <label class="col-sm-24 light">{{output.outputInstance}}</label> + </div> + </div> + </div> +</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/index.html ---------------------------------------------------------------------- diff --git a/falcon-ui/app/index.html b/falcon-ui/app/index.html index 2552194..13fbe35 100644 --- a/falcon-ui/app/index.html +++ b/falcon-ui/app/index.html @@ -27,19 +27,18 @@ <link rel="icon" type="image/x-icon" href="data:image/png;base64,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"/> </head> - <body ng-cloak ng-controller="RootCtrl"> - - <section class="container-fluid"> - <header class="row" nav-header></header> - <server-messages></server-messages> - </section> - - <section class="container-fluid"> - <div class="row mainUIView" ui-view></div> - </section> - - <script src="js/vendor.min.js"></script> - <script src="js/main.min.js"></script> - + <body ng-cloak ng-controller="RootCtrl" id="body"> + + <section class="container-fluid"> + <header class="row" nav-header id="mainHeader"></header> + </section> + + <section class="container-fluid"> + <div class="row mainUIView" ui-view id="mainUIView"></div> + </section> + + <script src="js/vendor.min.js"></script> + <script src="js/main.min.js"></script> + </body> </html> http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/js/app.js ---------------------------------------------------------------------- diff --git a/falcon-ui/app/js/app.js b/falcon-ui/app/js/app.js index 1705cb4..5ae7eb6 100644 --- a/falcon-ui/app/js/app.js +++ b/falcon-ui/app/js/app.js @@ -19,15 +19,25 @@ 'use strict'; var app = angular.module('app', [ - 'ui.bootstrap', 'ui.router', 'ngCookies', 'ngAnimate', 'ngMessages', 'checklist-model', 'app.controllers', 'app.directives', 'app.services' + 'ui.bootstrap', + 'ui.router', + 'ngCookies', + 'ngAnimate', + 'ngMessages', + 'checklist-model', + 'app.controllers', + 'app.directives', + 'app.services', + 'ngTagsInput', + 'nsPopover', 'ngAnimate', 'ngMask', 'dateHelper' ]); app.config(["$stateProvider", "$urlRouterProvider", "$httpProvider", function ($stateProvider, $urlRouterProvider, $httpProvider) { - - $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content'); - - $httpProvider.defaults.headers.common["X-Requested-By"] = 'X-Requested-By'; - + + $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content'); + + $httpProvider.defaults.headers.common["X-Requested-By"] = 'X-Requested-By'; + $urlRouterProvider.otherwise("/"); $stateProvider @@ -36,9 +46,16 @@ templateUrl: 'html/mainTpl.html', controller: 'DashboardCtrl' }) - .state('entityDetails', { - controller: 'EntityDetailsCtrl', - templateUrl: 'html/entityDetailsTpl.html' + .state('authenticating', { + templateUrl: 'html/authenticating.html' + }) + .state('login', { + controller: 'LoginFormCtrl', + templateUrl: 'html/login.html' + }) + .state('entityDefinition', { + controller: 'EntityDefinitionCtrl', + templateUrl: 'html/entityDefinitionTpl.html' }) .state('forms', { templateUrl: 'html/formsTpl.html' @@ -73,9 +90,9 @@ templateUrl: 'html/feed/feedFormClustersStepTpl.html', controller: 'FeedClustersController', resolve: { - clustersList: ['Falcon', function(Falcon) { + clustersList: ['Falcon', function (Falcon) { return Falcon.getEntities('cluster').then( - function(response) { + function (response) { return response.data; }); }] @@ -101,9 +118,9 @@ templateUrl: 'html/process/processFormClustersStepTpl.html', controller: 'ProcessClustersCtrl', resolve: { - clustersList: ['Falcon', function(Falcon) { + clustersList: ['Falcon', function (Falcon) { return Falcon.getEntities('cluster').then( - function(response) { + function (response) { return response.data; }); }] @@ -113,9 +130,9 @@ templateUrl: 'html/process/processFormInputsAndOutputsStepTpl.html', controller: 'ProcessInputsAndOutputsCtrl', resolve: { - feedsList: ['Falcon', function(Falcon) { + feedsList: ['Falcon', function (Falcon) { return Falcon.getEntities('feed').then( - function(response) { + function (response) { return response.data; }); }] @@ -124,18 +141,201 @@ .state('forms.process.summary', { templateUrl: 'html/process/processFormSummaryStepTpl.html', controller: 'ProcessSummaryCtrl' - }); - + }) + .state('entityDetails', { + views: { + '': { + controller: 'EntityDetailsCtrl', + templateUrl: 'html/entityDetailsTpl.html' + }, + 'feedSummary@entityDetails': { + templateUrl: 'html/feed/feedSummary.html' + }, + 'processSummary@entityDetails': { + templateUrl: 'html/process/processSummary.html' + } + } + }) + .state('forms.dataset', { + controller: 'DatasetCtrl', + templateUrl: 'html/dataset/datasetFormTpl.html', + resolve: { + clustersList: ['Falcon', function (Falcon) { + return Falcon.getEntities('cluster').then( + function (response) { + return response.data.entity; + }); + }] + } + }) + .state('forms.dataset.general', { + templateUrl: 'html/dataset/datasetFormGeneralStepTpl.html' + }) + .state('forms.dataset.summary', { + templateUrl: 'html/dataset/datasetFormSummaryStepTpl.html' + }) + .state('instanceDetails', { + templateUrl: 'html/instanceDetails.html', + controller: 'InstanceDetailsCtrl' + }) + ; + }]); - app.run(['$rootScope', - function ($rootScope) { - - $rootScope.$on('$stateChangeError', - function(event, toState, toParams, fromState, fromParams, error){ - console.log('Manual log of stateChangeError: ' + error); + app.run(['$rootScope', '$state', '$location', '$http', '$stateParams', '$cookieStore', 'SpinnersFlag', 'ServerAPI', '$timeout', '$interval', + function ($rootScope, $state, $location, $http, $stateParams, $cookieStore, SpinnersFlag, ServerAPI, $timeout, $interval) { + + if(!$rootScope.secureModeDefined){ + $rootScope.secureMode = false; + ServerAPI.clearUser().then(function() { + ServerAPI.getServerConfig().then(function() { + if (ServerAPI.data) { + ServerAPI.data.properties.forEach(function(property) { + if(property.key == 'authentication'){ + if(property.value == 'kerberos'){ + $rootScope.secureMode = true; + } + } + }); + } + $rootScope.secureModeDefined = true; + }); + }); + } + + var location = $location.absUrl(); + var index = location.indexOf("views/"); + if (index !== -1) { + index = index + 6; + var path = location.substring(index); + var servicePaths = path.split("/"); + $rootScope.serviceURI = '/api/v1/views/' + servicePaths[0] + '/versions/' + servicePaths[1] + '/instances/' + servicePaths[2] + '/resources/proxy'; + } + + $rootScope.ambariView = function () { + var location_call = $location.absUrl(); + var index_call = location_call.indexOf("views/"); + if (index_call !== -1) { + return true; + } else { + return false; + } + }; + + $rootScope.isSecureMode = function () { + if(!$rootScope.secureModeDefined){ + return false; + }else if ($rootScope.secureMode) { + return true; + }else { + return false; + } + }; + + $rootScope.userLogged = function () { + if($rootScope.ambariView()){ + return true; + } else { + if (angular.isDefined($cookieStore.get('userToken')) && $cookieStore.get('userToken') !== null) { + return true; + } else { + return false; + } + } + }; + + //$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) { + $rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from) { + SpinnersFlag.show = false; + SpinnersFlag.backShow = false; + + $rootScope.previousState = from.name; + $rootScope.currentState = to.name; }); - - }]); + + $rootScope.$on('$stateChangeError', + //function(event, toState, toParams, fromState, fromParams, error){ + function (event, toState, toParams, fromState, error) { + console.log('Manual log of stateChangeError: ' + error); + }); + + var checkRedirect = function(event, toState){ + if (toState.name !== 'login') { + if ($rootScope.ambariView()) { + + if (angular.isDefined($cookieStore.get('userToken')) && $cookieStore.get('userToken') !== null) { + + } else { + event.preventDefault(); + $http.get($rootScope.serviceURI).success(function (data) { + var userToken = {}; + userToken.user = data; + $cookieStore.put('userToken', userToken); + $state.transitionTo('main'); + }); + } + + }else if ($rootScope.secureMode) { + + ServerAPI.getCurrentUser().then(function() { + var userToken = {}; + userToken.user = ServerAPI.user; + $cookieStore.put('userToken', userToken); + $state.transitionTo('main'); + }); + + }else if ($rootScope.userLogged()) { + + var userToken = $cookieStore.get('userToken'); + var timeOut = new Date().getTime(); + timeOut = timeOut - userToken.timeOut; + if (timeOut > userToken.timeOutLimit) { + $cookieStore.put('userToken', null); + event.preventDefault(); + $state.transitionTo('login'); + } else { + userToken.timeOut = new Date().getTime(); + $cookieStore.put('userToken', userToken); + } + + } else { + event.preventDefault(); + $state.transitionTo('login'); + } + } + }; + + $rootScope.$on('$stateChangeStart', + function (event, toState) { + if ($rootScope.userLogged()) { + var userToken = $cookieStore.get('userToken'); + var timeOut = new Date().getTime(); + timeOut = timeOut - userToken.timeOut; + if (timeOut > userToken.timeOutLimit) { + $cookieStore.put('userToken', null); + event.preventDefault(); + $state.transitionTo('login'); + } else { + userToken.timeOut = new Date().getTime(); + $cookieStore.put('userToken', userToken); + } + }else{ + var interval; + if(!$rootScope.secureModeDefined){ + if (toState.name !== 'authenticating') { + event.preventDefault(); + $state.transitionTo('authenticating'); + } + interval = $interval(function() { + if($rootScope.secureModeDefined){ + $interval.cancel(interval); + checkRedirect(event, toState); + } + }, 1000); + } + } + }); + + }]); })(); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/js/controllers/cluster/cluster-module.js ---------------------------------------------------------------------- diff --git a/falcon-ui/app/js/controllers/cluster/cluster-module.js b/falcon-ui/app/js/controllers/cluster/cluster-module.js index d00a937..d0fdf86 100644 --- a/falcon-ui/app/js/controllers/cluster/cluster-module.js +++ b/falcon-ui/app/js/controllers/cluster/cluster-module.js @@ -26,9 +26,10 @@ */ var clusterModule = angular.module('app.controllers.cluster', [ 'app.services' ]); - clusterModule.controller('ClusterFormCtrl', [ - "$scope", "$interval", "Falcon", "EntityModel", "$state", "X2jsService", "ValidationService", - function ($scope, $interval, Falcon, EntityModel, $state, X2jsService, validationService) { + clusterModule.controller('ClusterFormCtrl', [ "$scope", "$interval", "Falcon", "EntityModel", "$state", + "X2jsService", "ValidationService", "SpinnersFlag", "$timeout", "$rootScope", "$cookieStore", + function ($scope, $interval, Falcon, EntityModel, $state, + X2jsService, validationService, SpinnersFlag, $timeout, $rootScope, $cookieStore) { $scope.clusterEntity = EntityModel; $scope.xmlPreview = { edit: false }; @@ -62,9 +63,11 @@ } //-------------ACL----------------// if (!$scope.clusterEntity.clusterModel.cluster.ACL) { - $scope.clusterEntity.clusterModel.cluster.ACL = { + angular.copy(EntityModel.defaultValues.cluster.cluster.ACL, $scope.clusterEntity.clusterModel.cluster.ACL); + $scope.clusterEntity.clusterModel.cluster.ACL._owner = $cookieStore.get('userToken').user; + /*$scope.clusterEntity.clusterModel.cluster.ACL = { _owner: "", _group: "", _permission: "" - }; + };*/ } //------------Location------------// modelLocationsArray.forEach(function(element) { @@ -117,20 +120,27 @@ $scope.removeLocation(lastLocationIndex); } //deletes ACL if empty - if ($scope.clusterEntity.clusterModel.cluster.ACL && + /*if ($scope.clusterEntity.clusterModel.cluster.ACL && $scope.clusterEntity.clusterModel.cluster.ACL._owner === "") { delete $scope.clusterEntity.clusterModel.cluster.ACL; - } + }*/ //deletes tags if empty - if ($scope.clusterEntity.clusterModel.cluster.tags.length === 0) { + if (!$scope.clusterEntity.clusterModel.cluster.tags) { delete $scope.clusterEntity.clusterModel.cluster.tags; } //moves properties to be the last element if acl exists $scope.arrangeFieldsOrder(); } - $scope.arrangeFieldsOrder = function () { - var BK = $scope.clusterEntity.clusterModel.cluster, - orderedObj = {}; + $scope.arrangeFieldsOrder = function (xmlObj) { + + var BK, + orderedObj = {}; + + if (xmlObj) { + BK = xmlObj.cluster; + } else { + BK = $scope.clusterEntity.clusterModel.cluster; + } orderedObj._xmlns = 'uri:falcon:cluster:0.1'; orderedObj._name = BK._name; @@ -161,10 +171,13 @@ }; $scope.splitTags = function () { $scope.tagsArray = []; - $scope.clusterEntity.clusterModel.cluster.tags.split(",").forEach(function (fieldToSplit) { - var splittedString = fieldToSplit.split("="); - $scope.tagsArray.push({key: splittedString[0], value: splittedString[1]}); - }); + if ($scope.clusterEntity.clusterModel.cluster.tags) { + $scope.clusterEntity.clusterModel.cluster.tags.split(",").forEach(function (fieldToSplit) { + var splittedString = fieldToSplit.split("="); + $scope.tagsArray.push({key: splittedString[0], value: splittedString[1]}); + }); + } + }; $scope.addTag = function () { $scope.tagsArray.push({key: null, value: null}); @@ -208,17 +221,23 @@ }; //--------------------------------------// $scope.goSummaryStep = function (formInvalid) { + SpinnersFlag.show = true; if (!$scope.validations.nameAvailable || formInvalid) { validationService.displayValidations.show = true; validationService.displayValidations.nameShow = true; + SpinnersFlag.show = false; return; } cleanModel(); $scope.secondStep = true; $state.go("forms.cluster.summary"); + $timeout(function () { + angular.element('.nextBtn').trigger('focus'); + }, 500); }; $scope.goGeneralStep = function () { + SpinnersFlag.backShow = true; $scope.secondStep = false; validationService.displayValidations.show = false; validationService.displayValidations.nameShow = false; @@ -239,19 +258,23 @@ } }; $scope.saveCluster = function () { + SpinnersFlag.show = true; $scope.saveModelBuffer(); Falcon.logRequest(); Falcon.postSubmitEntity($scope.jsonString, "cluster").success(function (response) { + $scope.skipUndo = true; Falcon.logResponse('success', response, false); $state.go('main'); }).error(function (err) { + SpinnersFlag.show = false; Falcon.logResponse('error', err, false); + angular.element('body, html').animate({scrollTop: 0}, 300); }); }; - + //--------------------------------------// //----------XML preview-----------------// - + $scope.xmlPreview.editXML = function () { $scope.xmlPreview.edit = !$scope.xmlPreview.edit; }; @@ -261,9 +284,15 @@ $scope.xml = xmlStr; }; $scope.transformBack = function() { + try { var xmlObj = X2jsService.xml_str2json($scope.prettyXml); - $scope.clusterEntity.clusterModel = xmlObj; + + if (!xmlObj.cluster.ACL || !xmlObj.cluster.ACL._owner || !xmlObj.cluster.ACL._group || !xmlObj.cluster.ACL._permission) { + xmlObj.cluster.ACL = angular.copy(EntityModel.defaultValues.cluster.cluster.ACL); + } + + $scope.arrangeFieldsOrder(xmlObj); if($scope.clusterEntity.clusterModel.cluster.properties && $scope.clusterEntity.clusterModel.cluster.properties.property[0] === '') { $scope.clusterEntity.clusterModel.cluster.properties.property=[]; @@ -272,6 +301,7 @@ catch(err) { console.log('xml malformed'); } + }; $scope.saveModelBuffer = function () { $scope.jsonString = angular.toJson($scope.clusterEntity.clusterModel); @@ -294,6 +324,24 @@ } var refresher = $interval(xmlPreviewCallback, 1000); + $scope.skipUndo = false; + $scope.$on('$destroy', function () { + var model = angular.copy($scope.clusterEntity.clusterModel.cluster), + defaultModel = angular.toJson(EntityModel.defaultValues.cluster.cluster); + + model.interfaces.interface.forEach(function (item, index) { + if (item._type === "registry" && item._endpoint === "" && item._version === "") { + model.interfaces.interface.splice(index, 1); + } + }); + + model = angular.toJson(model); + + if (!$scope.skipUndo && !angular.equals(model, defaultModel)) { + $interval.cancel(refresher); + $scope.$parent.cancel('cluster', $rootScope.previousState); + } + }); //------------init------------// normalizeModel(); http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/js/controllers/controllers.js ---------------------------------------------------------------------- diff --git a/falcon-ui/app/js/controllers/controllers.js b/falcon-ui/app/js/controllers/controllers.js index 9fa878e..4867851 100644 --- a/falcon-ui/app/js/controllers/controllers.js +++ b/falcon-ui/app/js/controllers/controllers.js @@ -17,8 +17,9 @@ */ (function () { 'use strict'; - + angular.module('app.controllers', [ + 'app.controllers.login', 'app.controllers.navHeader', 'app.controllers.rootCtrl', 'app.controllers.dashboardCtrl', @@ -26,7 +27,9 @@ 'app.controllers.cluster', 'app.controllers.feed', 'app.controllers.process', - 'app.controllers.entity' + 'app.controllers.entity', + 'app.controllers.instance', + 'app.controllers.dataset' ]); })(); http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/js/controllers/dashboard-controller.js ---------------------------------------------------------------------- diff --git a/falcon-ui/app/js/controllers/dashboard-controller.js b/falcon-ui/app/js/controllers/dashboard-controller.js index bd60736..7a8d1b4 100644 --- a/falcon-ui/app/js/controllers/dashboard-controller.js +++ b/falcon-ui/app/js/controllers/dashboard-controller.js @@ -21,79 +21,103 @@ var dashboardCtrlModule = angular.module('app.controllers.dashboardCtrl', ['app.services']); dashboardCtrlModule.controller('DashboardCtrl', [ "$scope", "Falcon", "EntityModel", "FileApi", "$state", "X2jsService", - function ($scope, Falcon, EntityModel, FileApi, $state, X2jsService) { - - $scope.$parent.refreshLists(); + "$timeout", function ($scope, Falcon, EntityModel, FileApi, $state, X2jsService, $timeout) { + + $scope.$parent.refreshList(); + + $timeout(function() { + angular.element('#nsPopover').trigger('click'); + }, 1000); + + $scope.focusSearch = function () { + $scope.$parent.refreshList($scope.tags); + }; $scope.deleteEntity = function (type, name) { type = type.toLowerCase(); //new sandbox returns uppercase type Falcon.logRequest(); Falcon.deleteEntity(type, name) - .success(function (data) { - Falcon.logResponse('success', data, type); - $scope.$parent.refreshList(type); + .success(function (data) { + Falcon.logResponse('success', data, type); + $scope.$parent.refreshList($scope.tags); }) .error(function (err) { - + Falcon.logResponse('error', err, type); }); }; $scope.cloneEntity = function (type, name) { type = type.toLowerCase(); //new sandbox returns uppercase type - + Falcon.logRequest(); Falcon.getEntityDefinition(type, name) .success(function (data) { Falcon.logResponse('success', data, false, true); var modelName = type + "Model", entityModel = X2jsService.xml_str2json(data); - - EntityModel[modelName] = entityModel; - EntityModel[modelName][type]._name = ""; - $scope.models[modelName] = angular.copy(entityModel); - $scope.cloningMode = true; // dont know utility of this - $scope.$parent.cloningMode = true; - $state.go('forms.' + type + ".general"); + + if (entityModel.process && entityModel.process.tags && entityModel.process.tags.search('_falcon_mirroring_type') !== -1) { + + entityModel.process.name = ""; + EntityModel.datasetModel.toImportModel = entityModel; + $scope.$parent.cloningMode = true; + $state.go('forms.dataset.general'); + + } else { + EntityModel[modelName] = entityModel; + EntityModel[modelName][type]._name = ""; + $scope.models[modelName] = angular.copy(entityModel); + $scope.cloningMode = true; // dont know utility of this + $scope.$parent.cloningMode = true; + $state.go('forms.' + type + ".general"); + } }) .error(function (err) { Falcon.logResponse('error', err, false, true); }); }; - $scope.editEntity = function (type, name) { + $scope.editEntity = function (type, name) { type = type.toLowerCase(); //new sandbox returns uppercase type - + Falcon.logRequest(); Falcon.getEntityDefinition(type, name) .success(function (data) { Falcon.logResponse('success', data, false, true); var entityModel = X2jsService.xml_str2json(data); var modelName = type + "Model"; - EntityModel[modelName] = entityModel; - $scope.models[modelName] = angular.copy(entityModel); - $scope.editingMode = true;// dont know utility of this - $scope.$parent.cloningMode = false; - $state.go('forms.' + type + ".general"); + + if (entityModel.process && entityModel.process.tags.search('_falcon_mirroring_type') !== -1) { + + EntityModel.datasetModel.toImportModel = entityModel; + $scope.$parent.cloningMode = false; + $state.go('forms.dataset.general'); + + } else { + EntityModel[modelName] = entityModel; + $scope.models[modelName] = angular.copy(entityModel); + $scope.editingMode = true;// dont know utility of this + $scope.$parent.cloningMode = false; + $state.go('forms.' + type + ".general"); + } }) .error(function (err) { Falcon.logResponse('error', err, false, true); }); }; //-----------------------------------------// - $scope.entityDetails = function (name, type) { + $scope.entityDefinition = function (name, type) { + type = type.toLowerCase(); //new sandbox returns uppercase type - + Falcon.logRequest(); Falcon.getEntityDefinition(type, name) .success(function (data) { Falcon.logResponse('success', data, false, true); var entityModel = X2jsService.xml_str2json(data); - var modelName = type + "Model"; - EntityModel[modelName] = entityModel; - $scope.models[modelName] = angular.copy(entityModel); - $scope.editingMode = true;// dont know utility of this - $scope.$parent.cloningMode = false; - //$state.go('forms.' + type + ".general"); - $state.go('entityDetails'); + EntityModel.type = type; + EntityModel.name = name; + EntityModel.model = entityModel; + $state.go('entityDefinition'); }) .error(function (err) { Falcon.logResponse('error', err, false, true); @@ -104,7 +128,7 @@ Falcon.logRequest(); Falcon.postResumeEntity(type, name).success(function (data) { Falcon.logResponse('success', data, type); - $scope.$parent.refreshList(type); + $scope.$parent.refreshList($scope.tags); }) .error(function (err) { Falcon.logResponse('error', err, type); @@ -114,7 +138,7 @@ Falcon.logRequest(); Falcon.postScheduleEntity(type, name).success(function (data) { Falcon.logResponse('success', data, type); - $scope.$parent.refreshList(type); + $scope.$parent.refreshList($scope.tags); }) .error(function (err) { Falcon.logResponse('error', err, type); @@ -125,19 +149,72 @@ Falcon.logRequest(); Falcon.postSuspendEntity(type, name) .success(function (message) { - Falcon.logResponse('success', message, type); - $scope.$parent.refreshList(type); + Falcon.logResponse('success', message, type); + $scope.$parent.refreshList($scope.tags); }) .error(function (err) { Falcon.logResponse('error', err, type); - + }); }; + + $scope.loadTags = function(query) { + var tags = new Array(); + if(!$scope.$parent.nameFounded){ + tags.push({ text: 'Name:' + query }); + } + if(!$scope.$parent.typeFounded){ + var queryAux = query.toUpperCase(); + if(queryAux === "F" || queryAux === "FE" || queryAux === "FEE" || queryAux === "FEED"){ + tags.push({ text: 'Type:feed'}); + } + if(queryAux === "P" || queryAux === "PR" || queryAux === "PRO" || queryAux === "PROC" || queryAux === "PROCE" + || queryAux === "PROCES" || queryAux === "PROCESS"){ + tags.push({ text: 'Type:process'}); + } + if(queryAux === "M" || queryAux === "MI" || queryAux === "MIR" || queryAux === "MIRR" || queryAux === "MIRRO" + || queryAux === "MIRROR"){ + tags.push({ text: 'Type:mirror'}); + } + } + if(query !== "*"){ + tags.push({ text: 'Tag:' + query }); + } + return tags; + }; + $scope.relationsEntity = function (type, name) { console.log("relations " + type + " - " + name); }; - - + + $scope.displayResults = function () { + $scope.$parent.refreshList($scope.tags); + }; + + $scope.entityDetails = function (name, type) { + + type = type.toLowerCase(); //new sandbox returns uppercase type + + Falcon.logRequest(); + Falcon.getEntityDefinition(type, name) + .success(function (data) { + Falcon.logResponse('success', data, false, true); + var entityModel = X2jsService.xml_str2json(data); + EntityModel.type = type; + EntityModel.name = name; + EntityModel.model = entityModel; + $state.go('entityDetails'); + }) + .error(function (err) { + Falcon.logResponse('error', err, false, true); + }); + }; + + $scope.clearTags = function(){ + $scope.tags = []; + $scope.$parent.refreshList($scope.tags); + }; + }]); })(); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/js/controllers/dataset/dataset-controller.js ---------------------------------------------------------------------- diff --git a/falcon-ui/app/js/controllers/dataset/dataset-controller.js b/falcon-ui/app/js/controllers/dataset/dataset-controller.js new file mode 100644 index 0000000..a28cd77 --- /dev/null +++ b/falcon-ui/app/js/controllers/dataset/dataset-controller.js @@ -0,0 +1,642 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function () { + 'use strict'; + + var datasetModule = angular.module('app.controllers.dataset', [ 'app.services' ]); + + datasetModule.controller('DatasetCtrl', [ + "$scope", "$interval", "Falcon", "EntityModel", "$state", "X2jsService", "DateHelper", + "ValidationService", "SpinnersFlag", "$timeout", "$rootScope", "clustersList", "$cookieStore", + function ($scope, $interval, Falcon, EntityModel, $state, X2jsService, DateHelper, + validationService, SpinnersFlag, $timeout, $rootScope, clustersList, $cookieStore) { + + + $scope.skipUndo = false; + $scope.$on('$destroy', function () { + + if (!$scope.skipUndo && !angular.equals($scope.UIModel, EntityModel.defaultValues.MirrorUIModel)) { + $scope.$parent.cancel('dataset', $rootScope.previousState); + } + }); + + $scope.isActive = function (route) { + return route === $state.current.name; + }; + + $scope.isCompleted = function (route) { + return $state.get(route).data && $state.get(route).data.completed; + }; + + $scope.clone = $scope.$parent.cloningMode; + + if (!clustersList) { + $scope.clustersList = []; + } else if (clustersList.type) { // is an object + $scope.clustersList = [clustersList]; + } else { + $scope.clustersList = clustersList; + } + + $scope.switchModel = function (type) { + $scope.model = EntityModel.datasetModel[type].process; + $scope.UIModel.formType = type; + $scope.completeModel = EntityModel.datasetModel[type]; + switchTag(type); + checkClusters(); + }; + $scope.model = EntityModel.datasetModel.HDFS.process; + $scope.UIModel = EntityModel.datasetModel.UIModel; + $scope.completeModel = EntityModel.datasetModel.HDFS; + + $scope.UIModel.acl.owner = $cookieStore.get('userToken').user; + + //-------------------------// + function checkClusters() { + if ($scope.UIModel.source.cluster && $scope.UIModel.formType === 'HIVE') { + $scope.getSourceDefinition(); + } + if ($scope.UIModel.target.cluster && $scope.UIModel.formType === 'HIVE') { + $scope.getTargetDefinition(); + } + } + $scope.checkFromSource = function () { + if ($scope.UIModel.source.location !== "HDFS") { + $scope.UIModel.target.location = "HDFS"; + $scope.UIModel.runOn = 'target'; + } + }; + $scope.checkFromTarget = function () { + if ($scope.UIModel.target.location !== "HDFS") { + $scope.UIModel.source.location = "HDFS"; + $scope.UIModel.runOn = 'source'; + } + }; + //----------------TAGS---------------------// + $scope.addTag = function () { + if ($scope.UIModel.tags.newTag.value === "_falcon_mirroring_type") { + return; + } + $scope.UIModel.tags.tagsArray.push($scope.UIModel.tags.newTag); + $scope.UIModel.tags.newTag = {value: "", key: ""}; + $scope.convertTags(); + }; + $scope.removeTag = function (index) { + $scope.UIModel.tags.tagsArray.splice(index, 1); + $scope.convertTags(); + }; + function switchTag (type) { + $scope.UIModel.tags.tagsArray.forEach(function (item) { + if (item.key === "_falcon_mirroring_type") { + item.value = type; + } + }); + } + $scope.convertTags = function () { + var result = []; + $scope.UIModel.tags.tagsArray.forEach(function (element) { + if (element.key && element.value) { + result.push(element.key + "=" + element.value); + } + }); + result = result.join(","); + $scope.UIModel.tags.tagsString = result; + }; + $scope.splitTags = function () { + $scope.UIModel.tags.tagsArray = []; + $scope.UIModel.tags.tagsString.split(",").forEach(function (fieldToSplit) { + var splittedString = fieldToSplit.split("="); + $scope.UIModel.tags.tagsArray.push({key: splittedString[0], value: splittedString[1]}); + }); + }; + //----------- Alerts -----------// + $scope.addAlert = function () { + $scope.UIModel.alerts.alertsArray.push($scope.UIModel.alerts.alert.email); + $scope.UIModel.alerts.alert = {email: ""}; + }; + $scope.removeAlert = function (index) { + $scope.UIModel.alerts.alertsArray.splice(index, 1); + }; + //----------------- DATE INPUTS -------------------// + $scope.dateFormat = 'MM/dd/yyyy'; + + $scope.openStartDatePicker = function ($event) { + $event.preventDefault(); + $event.stopPropagation(); + $scope.startOpened = true; + }; + $scope.openEndDatePicker = function ($event) { + $event.preventDefault(); + $event.stopPropagation(); + $scope.endOpened = true; + }; + + $scope.constructDate = function () { + + if ($scope.UIModel.validity.start && $scope.UIModel.validity.end && $scope.UIModel.validity.startTime && $scope.UIModel.validity.endTime) { + $scope.UIModel.validity.startISO = DateHelper.createISO($scope.UIModel.validity.start, $scope.UIModel.validity.startTime, $scope.UIModel.validity.tz); + $scope.UIModel.validity.endISO = DateHelper.createISO($scope.UIModel.validity.end, $scope.UIModel.validity.endTime, $scope.UIModel.validity.tz); + } + + }; + $scope.$watch(function () { + return $scope.UIModel.validity.tz; + }, function () { + return $scope.constructDate(); + }); + + //-------------------------------------// + + $scope.goNext = function (formInvalid, stateName) { + $state.current.data = $state.current.data || {}; + $state.current.data.completed = !formInvalid; + + SpinnersFlag.show = true; + if (!validationService.nameAvailable || formInvalid) { + validationService.displayValidations.show = true; + validationService.displayValidations.nameShow = true; + SpinnersFlag.show = false; + angular.element('body, html').animate({scrollTop: 0}, 500); + return; + } + validationService.displayValidations.show = false; + validationService.displayValidations.nameShow = false; + $scope.convertTags(); + createXML(); + $state.go(stateName); + angular.element('body, html').animate({scrollTop: 0}, 500); + }; + + $scope.goBack = function (stateName) { + SpinnersFlag.backShow = true; + validationService.displayValidations.show = false; + validationService.displayValidations.nameShow = false; + $state.go(stateName); + angular.element('body, html').animate({scrollTop: 0}, 500); + }; + + $scope.sourceClusterModel = {}; + $scope.targetClusterModel = {}; + + $scope.getSourceDefinition = function () { // only fills general step info, rest of operations performed in createXml + Falcon.getEntityDefinition("cluster", $scope.UIModel.source.cluster) + .success(function (data) { + $scope.sourceClusterModel = X2jsService.xml_str2json(data); + if (!EntityModel.datasetModel.UIModel.hiveOptions.source.stagingPath && EntityModel.datasetModel.UIModel.formType === 'HIVE') { + EntityModel.datasetModel.UIModel.hiveOptions.source.stagingPath = findLocation($scope.sourceClusterModel.cluster.locations.location, 'staging'); + } + if (!EntityModel.datasetModel.UIModel.hiveOptions.source.hiveServerToEndpoint && EntityModel.datasetModel.UIModel.formType === 'HIVE') { + EntityModel.datasetModel.UIModel.hiveOptions.source.hiveServerToEndpoint = replaceHive(findInterface($scope.sourceClusterModel.cluster.interfaces.interface, 'registry')); + } + + }) + .error(function (err) { + $scope.UIModel.source.cluster = ""; + Falcon.logResponse('error', err, false, true); + }); + }; + $scope.getTargetDefinition = function () { + Falcon.getEntityDefinition("cluster", $scope.UIModel.target.cluster) + .success(function (data) { + $scope.targetClusterModel = X2jsService.xml_str2json(data); + if (!EntityModel.datasetModel.UIModel.hiveOptions.target.stagingPath && EntityModel.datasetModel.UIModel.formType === 'HIVE') { + EntityModel.datasetModel.UIModel.hiveOptions.target.stagingPath = findLocation($scope.targetClusterModel.cluster.locations.location, 'staging'); + } + if (!EntityModel.datasetModel.UIModel.hiveOptions.target.hiveServerToEndpoint && EntityModel.datasetModel.UIModel.formType === 'HIVE') { + EntityModel.datasetModel.UIModel.hiveOptions.target.hiveServerToEndpoint = replaceHive(findInterface($scope.targetClusterModel.cluster.interfaces.interface, 'registry')); + } + }) + .error(function (err) { + $scope.UIModel.target.cluster = ""; + Falcon.logResponse('error', err, false, true); + }); + }; + + function findLocation (array, locationString) { + var loc = ""; + array.forEach(function (item) { + if (item._name === locationString) { + loc = item._path; + } + }); + return loc; + } + function findInterface(array, interfaceString) { + var inter = ""; + array.forEach(function (item) { + if (item._type === interfaceString) { + inter = item._endpoint; + } + }); + return inter; + } + + function replaceHive(string) { + if (string) { + var splitted = string.split(':'); + var uri = 'hive2' + ':' + splitted[1] + ':10000'; + return uri; + } + } + + function createXML() { + $scope.model._name = $scope.UIModel.name; + $scope.model.tags = $scope.UIModel.tags.tagsString; + $scope.model.retry._policy = $scope.UIModel.retry.policy; + $scope.model.retry._delay = $scope.UIModel.retry.delay.unit + '(' + $scope.UIModel.retry.delay.number + ')'; + $scope.model.retry._attempts = $scope.UIModel.retry.attempts; + $scope.model.ACL._owner = $scope.UIModel.acl.owner; + $scope.model.ACL._group = $scope.UIModel.acl.group; + $scope.model.ACL._permission = $scope.UIModel.acl.permissions; + $scope.model.frequency = $scope.UIModel.frequency.unit + '(' + $scope.UIModel.frequency.number + ')'; + $scope.model.clusters.cluster[0].validity._start = $scope.UIModel.validity.startISO; + $scope.model.clusters.cluster[0].validity._end = $scope.UIModel.validity.endISO; + $scope.model.timezone = $scope.UIModel.validity.tz; + if ($scope.UIModel.formType === 'HDFS') { + + if ($scope.UIModel.runOn === "source") { + $scope.model.clusters.cluster[0]._name = $scope.UIModel.source.cluster; + } else { + $scope.model.clusters.cluster[0]._name = $scope.UIModel.target.cluster; + } + + $scope.model.workflow._name = $scope.UIModel.name + '-WF'; + + $scope.model.properties.property.forEach(function (item) { + if (item._name === 'distcpMaxMaps') { + item._value = $scope.UIModel.allocation.hdfs.maxMaps; + } + if (item._name === 'distcpMapBandwidth') { + item._value = $scope.UIModel.allocation.hdfs.maxBandwidth; + } + if (item._name === 'drSourceDir') { + item._value = $scope.UIModel.source.path; + } + if (item._name === 'drTargetDir') { + item._value = $scope.UIModel.target.path; + } + if (item._name === 'drSourceClusterFS') { + if ($scope.UIModel.source.location === 'HDFS') { + item._value = findInterface($scope.sourceClusterModel.cluster.interfaces.interface, 'write'); + } else { + item._value = $scope.UIModel.source.url; + } + } + if (item._name === 'drTargetClusterFS') { + if ($scope.UIModel.target.location === 'HDFS') { + item._value = findInterface($scope.targetClusterModel.cluster.interfaces.interface, 'write'); + } else { + item._value = $scope.UIModel.target.url; + } + } + if (item._name === 'drNotificationReceivers') { + item._value = (function () { + if ($scope.UIModel.alerts.alertsArray.length === 0) { + return "NA"; + } else { + return $scope.UIModel.alerts.alertsArray.join(); + } + }()); + } + if (item._name === 'sourceCluster') { + if ($scope.UIModel.source.location === 'HDFS') { item._value = $scope.UIModel.source.cluster; } + else { item._value = ""; } + } + if (item._name === 'targetCluster') { + if ($scope.UIModel.target.location === 'HDFS') { item._value = $scope.UIModel.target.cluster; } + else { item._value = ""; } + } + }); + + } else if ($scope.UIModel.formType === 'HIVE') { + + $scope.model.clusters.cluster[0]._name = $scope.UIModel.source.cluster; + $scope.model.properties.property.forEach(function (item) { + if (item._name === 'distcpMaxMaps') { + item._value = $scope.UIModel.allocation.hive.maxMapsDistcp; + } + if (item._name === 'distcpMapBandwidth') { + item._value = $scope.UIModel.allocation.hive.maxBandwidth; + } + if (item._name === 'sourceCluster') { + item._value = $scope.UIModel.source.cluster; + } + if (item._name === 'targetCluster') { + item._value = $scope.UIModel.target.cluster; + } + if (item._name === 'sourceHiveServer2Uri') { + item._value = $scope.UIModel.hiveOptions.source.hiveServerToEndpoint; + } + if (item._name === 'targetHiveServer2Uri') { + item._value = $scope.UIModel.hiveOptions.target.hiveServerToEndpoint; + } + if (item._name === 'sourceStagingPath') { + item._value = $scope.UIModel.hiveOptions.source.stagingPath; + } + if (item._name === 'targetStagingPath') { + item._value = $scope.UIModel.hiveOptions.target.stagingPath; + } + if (item._name === 'sourceNN') { + item._value = findInterface($scope.sourceClusterModel.cluster.interfaces.interface, 'write'); + } + if (item._name === 'targetNN') { + item._value = findInterface($scope.targetClusterModel.cluster.interfaces.interface, 'write'); + } + if (item._name === 'sourceMetastoreUri') { + item._value = findInterface($scope.sourceClusterModel.cluster.interfaces.interface, 'registry'); + } + if (item._name === 'targetMetastoreUri') { + item._value = findInterface($scope.targetClusterModel.cluster.interfaces.interface, 'registry'); + } + if (item._name === 'sourceTable') { + if ($scope.UIModel.source.hiveDatabaseType === "databases") { + item._value = "*"; + } else { + item._value = $scope.UIModel.source.hiveTables; + } + } + if (item._name === 'sourceDatabase') { + if ($scope.UIModel.source.hiveDatabaseType === "databases") { + item._value = $scope.UIModel.source.hiveDatabases; + } else { + item._value = $scope.UIModel.source.hiveDatabase; + } + } + if (item._name === 'maxEvents') { + item._value = $scope.UIModel.allocation.hive.maxMapsEvents; + } + if (item._name === 'replicationMaxMaps') { + item._value = $scope.UIModel.allocation.hive.maxMapsMirror; + } + if (item._name === 'clusterForJobRun') { + if ($scope.UIModel.runOn === "source") { + item._value = $scope.UIModel.source.cluster; + } else { + item._value = $scope.UIModel.target.cluster; + } + } + if (item._name === 'clusterForJobRunWriteEP') { + if ($scope.UIModel.runOn === "source") { + item._value = findInterface($scope.sourceClusterModel.cluster.interfaces.interface, 'write'); + } else { + item._value = findInterface($scope.targetClusterModel.cluster.interfaces.interface, 'write'); + } + } + if (item._name === 'drJobName') { + item._value = $scope.UIModel.name; + } + if (item._name === 'drNotificationReceivers') { + item._value = (function () { + if ($scope.UIModel.alerts.alertsArray.length === 0) { + return "NA"; + } else { + return $scope.UIModel.alerts.alertsArray.join(); + } + }()); + } + + }); + + } else { + console.log('error in form type'); + } + + $scope.xmlString = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + X2jsService.json2xml_str($scope.completeModel); + + } + + $scope.save = function () { + SpinnersFlag.show = true; + + if(!$scope.$parent.cloningMode) { + Falcon.postUpdateEntity($scope.xmlString, 'process', $scope.model._name) + .success(function (response) { + $scope.skipUndo = true; + Falcon.logResponse('success', response, false); + $state.go('main'); + + }) + .error(function (err) { + SpinnersFlag.show = false; + Falcon.logResponse('error', err, false); + angular.element('body, html').animate({scrollTop: 0}, 300); + }); + } else { + Falcon.postSubmitEntity($scope.xmlString, 'process') + .success(function (response) { + $scope.skipUndo = true; + Falcon.logResponse('success', response, false); + $state.go('main'); + }) + .error(function (err) { + Falcon.logResponse('error', err, false); + SpinnersFlag.show = false; + angular.element('body, html').animate({scrollTop: 0}, 300); + }); + } + + }; + + function identifyLocationType (val) { + if (validationService.patterns.s3.test(val)) { + return "s3"; + } else if (validationService.patterns.azure.test(val)) { + return "azure"; + } else { + return "HDFS"; + } + } + + function importModel(model) { + + var mirrorType; + + if (model.process.tags.search('_falcon_mirroring_type=HDFS') !== -1) { + mirrorType = 'HDFS'; + } else { + mirrorType = 'HIVE'; + } + $scope.switchModel(mirrorType); + EntityModel.datasetModel.UIModel.formType = mirrorType; + EntityModel.datasetModel.UIModel.name = (function () { if (!$scope.clone) { return model.process._name; } else { return ""; } }()); + EntityModel.datasetModel.UIModel.retry.policy = model.process.retry._policy; + EntityModel.datasetModel.UIModel.retry.attempts = model.process.retry._attempts; + EntityModel.datasetModel.UIModel.retry.delay.number = (function () { + return parseInt(model.process.retry._delay.split('(')[1]); + }()); + EntityModel.datasetModel.UIModel.retry.delay.unit = (function () { + return model.process.retry._delay.split('(')[0]; + }()); + EntityModel.datasetModel.UIModel.frequency.number = (function () { + return parseInt(model.process.frequency.split('(')[1]); + }()); + EntityModel.datasetModel.UIModel.frequency.unit = (function () { + return model.process.frequency.split('(')[0]; + }()); + EntityModel.datasetModel.UIModel.acl.owner = model.process.ACL._owner; + EntityModel.datasetModel.UIModel.acl.group = model.process.ACL._group; + EntityModel.datasetModel.UIModel.acl.permissions = model.process.ACL._permission; + + EntityModel.datasetModel.UIModel.validity.startISO = model.process.clusters.cluster[0].validity._start; + EntityModel.datasetModel.UIModel.validity.endISO = model.process.clusters.cluster[0].validity._end; + EntityModel.datasetModel.UIModel.validity.tz = model.process.timezone; + EntityModel.datasetModel.UIModel.validity.start = DateHelper.importDate (model.process.clusters.cluster[0].validity._start, model.process.timezone); + EntityModel.datasetModel.UIModel.validity.startTime = DateHelper.importDate (model.process.clusters.cluster[0].validity._start, model.process.timezone); + EntityModel.datasetModel.UIModel.validity.end = DateHelper.importDate (model.process.clusters.cluster[0].validity._end, model.process.timezone); + EntityModel.datasetModel.UIModel.validity.endTime = DateHelper.importDate (model.process.clusters.cluster[0].validity._end, model.process.timezone); + + EntityModel.datasetModel.UIModel.tags.tagsString = model.process.tags; + EntityModel.datasetModel.UIModel.tags.tagsArray = (function () { + var array = []; + model.process.tags.split(',').forEach(function (fieldToSplit) { + var splittedString = fieldToSplit.split("="); + array.push({key: splittedString[0], value: splittedString[1]}); + }); + return array; + }()); + + if (mirrorType === 'HDFS') { + model.process.properties.property.forEach(function (item) { + if (item._name === 'distcpMaxMaps') { + EntityModel.datasetModel.UIModel.allocation.hdfs.maxMaps = item._value; + } + if (item._name === 'distcpMapBandwidth') { + EntityModel.datasetModel.UIModel.allocation.hdfs.maxBandwidth = item._value; + } + if (item._name === 'drSourceDir') { + EntityModel.datasetModel.UIModel.source.path = item._value; + } + if (item._name === 'drTargetDir') { + EntityModel.datasetModel.UIModel.target.path = item._value; + } + if (item._name === 'drNotificationReceivers') { + EntityModel.datasetModel.UIModel.alerts.alertsArray = (function () { + if (item._value !== "NA") { + return item._value.split(','); + } else { + return []; + } + }()); + } + if (item._name === 'targetCluster') { + EntityModel.datasetModel.UIModel.target.cluster = item._value; + } + if (item._name === 'sourceCluster') { + EntityModel.datasetModel.UIModel.source.cluster = item._value; + } + if (item._name === 'drSourceClusterFS') { + EntityModel.datasetModel.UIModel.source.url = item._value; + } + if (item._name === 'drTargetClusterFS') { + EntityModel.datasetModel.UIModel.target.url = item._value; + } + }); + + if (EntityModel.datasetModel.UIModel.source.cluster === model.process.clusters.cluster[0]._name) { + EntityModel.datasetModel.UIModel.runOn = "source"; + } + if (EntityModel.datasetModel.UIModel.target.cluster === model.process.clusters.cluster[0]._name) { + EntityModel.datasetModel.UIModel.runOn = "target"; + } + + EntityModel.datasetModel.UIModel.source.location = identifyLocationType(EntityModel.datasetModel.UIModel.source.url); + EntityModel.datasetModel.UIModel.target.location = identifyLocationType(EntityModel.datasetModel.UIModel.target.url); + + } else if (mirrorType === 'HIVE') { + + model.process.properties.property.forEach(function (item) { + if (item._name === 'distcpMaxMaps') { + EntityModel.datasetModel.UIModel.allocation.hive.maxMapsDistcp = item._value; + } + if (item._name === 'distcpMapBandwidth') { + EntityModel.datasetModel.UIModel.allocation.hive.maxBandwidth = item._value; + } + if (item._name === 'sourceCluster') { + EntityModel.datasetModel.UIModel.source.cluster = item._value; + } + if (item._name === 'targetCluster') { + EntityModel.datasetModel.UIModel.target.cluster = item._value; + } + if (item._name === 'sourceStagingPath') { + EntityModel.datasetModel.UIModel.hiveOptions.source.stagingPath = item._value; + } + if (item._name === 'targetStagingPath') { + EntityModel.datasetModel.UIModel.hiveOptions.target.stagingPath = item._value; + if (item._value === "*") { + EntityModel.datasetModel.UIModel.source.hiveDatabaseType = "databases"; + } else { + EntityModel.datasetModel.UIModel.source.hiveDatabaseType = "tables"; + } + } + if (item._name === 'sourceHiveServer2Uri') { + EntityModel.datasetModel.UIModel.hiveOptions.source.hiveServerToEndpoint = item._value; + } + if (item._name === 'targetHiveServer2Uri') { + EntityModel.datasetModel.UIModel.hiveOptions.target.hiveServerToEndpoint = item._value; + } + if (item._name === 'sourceTable') { + EntityModel.datasetModel.UIModel.source.hiveTables = item._value; + if (EntityModel.datasetModel.UIModel.source.hiveDatabaseType === "databases") { + EntityModel.datasetModel.UIModel.source.hiveTables = "*"; + } + else { + EntityModel.datasetModel.UIModel.source.hiveTables = item._value; + } + } + if (item._name === 'sourceDatabase') { + if (EntityModel.datasetModel.UIModel.source.hiveDatabaseType === "databases") { + EntityModel.datasetModel.UIModel.source.hiveDatabases = item._value; + } else { + EntityModel.datasetModel.UIModel.source.hiveDatabase = item._value; + } + } + if (item._name === 'maxEvents') { + EntityModel.datasetModel.UIModel.allocation.hive.maxMapsEvents = item._value; + } + if (item._name === 'replicationMaxMaps') { + EntityModel.datasetModel.UIModel.allocation.hive.maxMapsMirror = item._value; + } + if (item._name === 'clusterForJobRun') { + if (EntityModel.datasetModel.UIModel.source.cluster === item._value) { + EntityModel.datasetModel.UIModel.runOn = "source"; + } else { + EntityModel.datasetModel.UIModel.runOn = "target"; + } + } + if (item._name === 'drNotificationReceivers') { + EntityModel.datasetModel.UIModel.alerts.alertsArray = (function () { + if (item._value !== "NA") { + return item._value.split(','); + } else { + return []; + } + }()); + } + + }); + } + + if(EntityModel.datasetModel.UIModel.source.cluster) { $scope.getSourceDefinition(); } + if(EntityModel.datasetModel.UIModel.target.cluster) { $scope.getTargetDefinition(); } + + } + if (EntityModel.datasetModel.toImportModel) { + importModel(EntityModel.datasetModel.toImportModel); + } + }]); +}()); http://git-wip-us.apache.org/repos/asf/falcon/blob/86180d93/falcon-ui/app/js/controllers/entity/entity-definition.js ---------------------------------------------------------------------- diff --git a/falcon-ui/app/js/controllers/entity/entity-definition.js b/falcon-ui/app/js/controllers/entity/entity-definition.js new file mode 100644 index 0000000..5afe400 --- /dev/null +++ b/falcon-ui/app/js/controllers/entity/entity-definition.js @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function () { + 'use strict'; + + /*** + * @ngdoc controller + * @name app.controllers.feed.FeedController + * @requires EntityModel the entity model to copy the feed entity from + * @requires Falcon the falcon service to talk with the Falcon REST API + */ + var clusterModule = angular.module('app.controllers.view', [ 'app.services' ]); + + clusterModule.controller('EntityDefinitionCtrl', [ + "$scope", "$interval", "Falcon", "EntityModel", "$state", "X2jsService", + function ($scope, $interval, Falcon, EntityModel, $state, X2jsService) { + + $scope.entity = EntityModel; + $scope.xmlPreview = { edit: false }; + + var xmlStr = X2jsService.json2xml_str(angular.copy($scope.entity.model)); + $scope.prettyXml = X2jsService.prettifyXml(xmlStr); + $scope.xml = xmlStr; + + } + ]); + + clusterModule.filter('titleCase', function() { + return function(input) { + input = input || ''; + return input.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); + }; + }); + +})();
