Repository: ambari Updated Branches: refs/heads/trunk 85ac3c22e -> 6a906e630
AMBARI-16103. Tez View : Equip the tez view shim to work with both version 1 & 2 of Tez UI. (Sreenath Somarajapuram via hitesh) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/6a906e63 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/6a906e63 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/6a906e63 Branch: refs/heads/trunk Commit: 6a906e6309d634461d683f38badc0b5440cff5e0 Parents: 85ac3c2 Author: Hitesh Shah <[email protected]> Authored: Wed Apr 27 11:29:36 2016 -0700 Committer: Hitesh Shah <[email protected]> Committed: Wed Apr 27 11:29:36 2016 -0700 ---------------------------------------------------------------------- contrib/views/tez/pom.xml | 29 +- .../resources/ui/ambari-scripts/init-view.js | 287 +++++++++++++++++++ .../views/tez/src/main/resources/ui/index.html | 50 ---- .../resources/ui/scripts/init-ambari-view.js | 229 --------------- 4 files changed, 313 insertions(+), 282 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/6a906e63/contrib/views/tez/pom.xml ---------------------------------------------------------------------- diff --git a/contrib/views/tez/pom.xml b/contrib/views/tez/pom.xml index 9e626b8..a40d6c8 100644 --- a/contrib/views/tez/pom.xml +++ b/contrib/views/tez/pom.xml @@ -103,12 +103,36 @@ <outputDirectory>target/classes</outputDirectory> </artifactItem> </artifactItems> - <includes>fonts/**/*, img/**/*, scripts/**/*, styles/**/*</includes> + <includes>fonts/**/*, img/**/*, scripts/**/*, assets/**/*, config/**/*, styles/**/*, index.html</includes> </configuration> </execution> </executions> </plugin> + <!-- Adds init view script to the UI --> + <plugin> + <groupId>com.google.code.maven-replacer-plugin</groupId> + <artifactId>replacer</artifactId> + <version>1.5.3</version> + <executions> + <execution> + <phase>process-resources</phase> + <goals> + <goal>replace</goal> + </goals> + </execution> + </executions> + <configuration> + <file>target/classes/index.html</file> + <replacements> + <replacement> + <token></body></token> + <value><script src="ambari-scripts/init-view.js"></script></body></value> + </replacement> + </replacements> + </configuration> + </plugin> + <plugin> <groupId>org.vafer</groupId> <artifactId>jdeb</artifactId> @@ -133,8 +157,7 @@ <directory>src/main/resources/ui</directory> <filtering>false</filtering> <includes> - <include>scripts/*</include> - <include>index.html</include> + <include>ambari-scripts/*</include> </includes> </resource> http://git-wip-us.apache.org/repos/asf/ambari/blob/6a906e63/contrib/views/tez/src/main/resources/ui/ambari-scripts/init-view.js ---------------------------------------------------------------------- diff --git a/contrib/views/tez/src/main/resources/ui/ambari-scripts/init-view.js b/contrib/views/tez/src/main/resources/ui/ambari-scripts/init-view.js new file mode 100644 index 0000000..4b7d94d --- /dev/null +++ b/contrib/views/tez/src/main/resources/ui/ambari-scripts/init-view.js @@ -0,0 +1,287 @@ +/** + * 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. + */ + +var PATH_PARAM_NAME = "viewPath"; + +/** + * Constructs URL for fetching Ambari view instance parameters. + * @return {String} + */ +function getStatusURL() { + var urlParts = location.pathname.split('/'); + + return "/api/v1/views/%@/versions/%@/instances/%@/resources/status".fmt( + urlParts[2], + urlParts[3], + urlParts[4] + ); +} + +function getStatus() { + var hashArray = location.pathname.split('/'); + + return $.ajax({ + type: 'GET', + dataType: 'json', + async: true, + context: this, + url: getStatusURL(), + }); +} + +/** + * Creates an object from query string + * @param getQueryObject {String} + * @return {Object} + */ +function getQueryObject(queryString) { + queryString = queryString ? queryString.replace('?', '') : ''; + + return queryString.split('&').reduce(function (obj, param) { + var paramParts; + if(param.trim()) { + paramParts = param.split('='); + if(paramParts[0] == PATH_PARAM_NAME) { + paramParts[1] = decodeURIComponent(paramParts[1]); + } + obj[paramParts[0]] = paramParts[1]; + } + return obj; + }, {}); +} + +/** + * Creates query string from an object + * @param getQueryObject {String} + * @return {Object} + */ +function getQueryString(object) { + var params = []; + + function addParam(key, value) { + params.push('%@=%@'.fmt(key, value)); + } + + object = $.extend({}, object); + + // Because of the way Ambari handles viewPath, its better to put it at the front + if(object.hasOwnProperty(PATH_PARAM_NAME)) { + addParam( + PATH_PARAM_NAME, + encodeURIComponent(object[PATH_PARAM_NAME]) + ); + delete object[PATH_PARAM_NAME]; + } + $.each(object, addParam); + + return params.join('&'); +} + +// Redirect if required +function redirectionCheck() { + var href = window.location.href; + + // Ember expects the url to have /#/ + if(href.indexOf('?') != -1 && href.indexOf('/#/') == -1) { + href = href.replace('?', '/#/?'); + } + + // If opened outside ambari, redirect + if(window.parent == window) { + var hrefParts = href.split('/#/'), + pathParts = hrefParts[1].split('?'), + queryParams =getQueryObject(pathParts[1]); + + if(pathParts[0]) { + queryParams[PATH_PARAM_NAME] = '/#/' + pathParts[0]; + } + + href = '%@?%@'.fmt( + hrefParts[0].replace('/views/', '/#/main/views/'), + getQueryString(queryParams) + ); + } + + // Normalize href + href = href.replace(/\/\//g, '/').replace(':/', '://'); + + if(href != window.location.href) { + window.location = href; + return true; + } +} + +// Force Ambari iframe to support fullscreen +function allowFullScreen() { + if(window.parent) { + var arrFrames = parent.document.getElementsByTagName("IFRAME"), + iframe; + for (var i = 0; i < arrFrames.length; i++) { + if (arrFrames[i].contentWindow === window) { + iframe = arrFrames[i]; + break; + } + } + + if(iframe) { + iframe.setAttribute('AllowFullScreen', true); + } + } +} + +// Replace Ambari's url on view URL change +function onPathChange() { + var path = window.location.hash.substr(2).trim(), + pathParts = path.split('?'), + + parentUrlParts = window.parent.location.href.split('?'), + parentQueryParam = getQueryObject(pathParts[1]); + + if(pathParts[0]) { + parentQueryParam[PATH_PARAM_NAME] = '/#/' + pathParts[0]; + } + + path = getQueryString(parentQueryParam); + window.parent.history.replaceState( + null, + null, + path ? '%@?%@'.fmt(parentUrlParts[0], path) : parentUrlParts[0] + ); +} + +function scheduleChangeHandler() { + if(typeof this._super === 'function') { + this._super.apply(this, arguments); + } + setTimeout(onPathChange, 100); +} + +function getConfigs(parameters) { + var host = window.location.protocol + + "//" + + window.location.hostname + + (window.location.port ? ':' + window.location.port: ''), + urlParts = location.pathname.split('/'), + resourcesPrefix = 'api/v1/views/%@/versions/%@/instances/%@/resources/'.fmt( + urlParts[2], + urlParts[3], + urlParts[4] + ); + + parameters = parameters || {}; + + return { + host: host, + yarnProtocol: parameters["yarn.protocol"], + resourcesPrefix: resourcesPrefix, + namespaces: { + webService: { + timeline: '%@atsproxy/ws/v1/timeline'.fmt(resourcesPrefix), + appHistory: '%@atsproxy/ws/v1/applicationhistory'.fmt(resourcesPrefix), + rm: '%@rmproxy/ws/v1/cluster'.fmt(resourcesPrefix), + am: '%@rmproxy/proxy/{app_id}/ws/v2/tez'.fmt(resourcesPrefix) + }, + web: { + rm: '%@rmredirect/cluster'.fmt(resourcesPrefix) + }, + } + }; +} + +function setUI1Configs(parameters) { + var configs = getConfigs(parameters); + + $.extend(true, App.Configs, { + envDefaults: { + isStandalone: false, + timelineBaseUrl: configs.host, + RMWebUrl: configs.host, + yarnProtocol: configs.yarnProtocol, + }, + restNamespace: { + timeline: configs.namespaces.webService.timeline, + applicationHistory: configs.namespaces.webService.appHistory, + + aminfo: '%@rmproxy/proxy/__app_id__/ws/v1/tez'.fmt(configs.resourcesPrefix), + aminfoV2: '%@rmproxy/proxy/__app_id__/ws/v2/tez'.fmt(configs.resourcesPrefix), + cluster: configs.namespaces.webService.rm + }, + otherNamespace: { + cluster: configs.namespaces.web.rm + } + }); + + App.TimelineRESTAdapter.reopen({ + namespace: App.Configs.restNamespace.timeline + }); +} + +function setUI2Configs(parameters) { + var configs = getConfigs(parameters); + + $.extend(true, ENV, { + isStandalone: false, + yarnProtocol: configs.yarnProtocol, + hosts: { + timeline: configs.host, + rm: configs.host, + }, + namespaces: configs.namespaces + }); +}; + +function setAppRoute(AppRoute) { + AppRoute.reopen({ + actions: { + didTransition: scheduleChangeHandler, + queryParamsDidChange: scheduleChangeHandler + } + }); +} + +function loadParams(app, callBack) { + app.deferReadiness(); + getStatus().always(function(status) { + callBack(status || {}); + app.advanceReadiness(); + }); +} + +if(!redirectionCheck()) { + var initializerOptions = { + name: 'configs', + }, + App = window.App; + + if(App) { + initializerOptions.initialize = function () { + setAppRoute(App.ApplicationRoute); + loadParams(App, setUI1Configs); + }; + } + else { + initializerOptions.before = 'env'; + initializerOptions.initialize = function (app) { + setAppRoute(app.get("__container__").lookup('route:application')); + loadParams(app, setUI2Configs); + }; + } + Ember.Application.initializer(initializerOptions); + + allowFullScreen(); +} http://git-wip-us.apache.org/repos/asf/ambari/blob/6a906e63/contrib/views/tez/src/main/resources/ui/index.html ---------------------------------------------------------------------- diff --git a/contrib/views/tez/src/main/resources/ui/index.html b/contrib/views/tez/src/main/resources/ui/index.html deleted file mode 100644 index ed0230a..0000000 --- a/contrib/views/tez/src/main/resources/ui/index.html +++ /dev/null @@ -1,50 +0,0 @@ -<!-- -* 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. ---> -<!doctype html> -<html> - <head> - <meta charset="utf-8"> - <title>Tez UI</title> - - <link rel="shortcut icon" href="img/tez-favicon.png" type="image/x-icon"> - - <link rel="stylesheet" href="styles/main.css"> - </head> - - <body> - <script src="scripts/components.js"></script> - <script src="scripts/templates.js"></script> - <script src="scripts/main.js"></script> - <script src="scripts/configs.js"></script> - - <script src="scripts/init-ambari-view.js"></script> - - <div class="error-bar" style="border: none;"> - <div class="main-container"> - <div class="message-container"> - <span class="error-icon"></span> - <span class="message"></span> - </div><div class="close-container"> - <div class="close">↓</div> - </div> - <div class="details"></div> - </div> - </div> - - </body> -</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/6a906e63/contrib/views/tez/src/main/resources/ui/scripts/init-ambari-view.js ---------------------------------------------------------------------- diff --git a/contrib/views/tez/src/main/resources/ui/scripts/init-ambari-view.js b/contrib/views/tez/src/main/resources/ui/scripts/init-ambari-view.js deleted file mode 100644 index 25d4da0..0000000 --- a/contrib/views/tez/src/main/resources/ui/scripts/init-ambari-view.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * 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. - */ - -App.deferReadiness(); - -var PATH_PARAM_NAME = "viewPath"; - -/** - * Constructs URL for fetching Ambari view instance parameters. - * @return {String} - */ -function getStatusURL() { - var urlParts = location.pathname.split('/'); - - return "/api/v1/views/%@/versions/%@/instances/%@/resources/status".fmt( - urlParts[2], - urlParts[3], - urlParts[4] - ); -} - -function getStatus() { - var hashArray = location.pathname.split('/'); - - return $.ajax({ - type: 'GET', - dataType: 'json', - async: true, - context: this, - url: getStatusURL(), - }); -} - -/** - * Creates an object from query string - * @param getQueryObject {String} - * @return {Object} - */ -function getQueryObject(queryString) { - queryString = queryString ? queryString.replace('?', '') : ''; - - return queryString.split('&').reduce(function (obj, param) { - var paramParts; - if(param.trim()) { - paramParts = param.split('='); - if(paramParts[0] == PATH_PARAM_NAME) { - paramParts[1] = decodeURIComponent(paramParts[1]); - } - obj[paramParts[0]] = paramParts[1]; - } - return obj; - }, {}); -} - -/** - * Creates query string from an object - * @param getQueryObject {String} - * @return {Object} - */ -function getQueryString(object) { - var params = []; - - function addParam(key, value) { - params.push('%@=%@'.fmt(key, value)); - } - - object = $.extend({}, object); - - // Because of the way Ambari handles viewPath, its better to put it at the front - if(object.hasOwnProperty(PATH_PARAM_NAME)) { - addParam( - PATH_PARAM_NAME, - encodeURIComponent(object[PATH_PARAM_NAME]) - ); - delete object[PATH_PARAM_NAME]; - } - $.each(object, addParam); - - return params.join('&'); -} - -// Redirect if required -function redirectionCheck() { - var href = window.location.href; - - // Ember expects the url to have /#/ - if(href.indexOf('?') != -1 && href.indexOf('/#/') == -1) { - href = href.replace('?', '/#/?'); - } - - // If opened outside ambari, redirect - if(window.parent == window) { - var hrefParts = href.split('/#/'), - pathParts = hrefParts[1].split('?'), - queryParams =getQueryObject(pathParts[1]); - - if(pathParts[0]) { - queryParams[PATH_PARAM_NAME] = '/#/' + pathParts[0]; - } - - href = '%@?%@'.fmt( - hrefParts[0].replace('/views/', '/#/main/views/'), - getQueryString(queryParams) - ); - } - - // Normalize href - href = href.replace(/\/\//g, '/').replace(':/', '://'); - - if(href != window.location.href) { - window.location = href; - return true; - } -} - -function allowFullScreen() { - if(window.parent) { - var arrFrames = parent.document.getElementsByTagName("IFRAME"), - iframe; - for (var i = 0; i < arrFrames.length; i++) { - if (arrFrames[i].contentWindow === window) { - iframe = arrFrames[i]; - break; - } - } - - if(iframe) { - iframe.setAttribute('AllowFullScreen', true); - } - } -} - -function onPathChange() { - var path = window.location.hash.substr(2).trim(), - pathParts = path.split('?'), - - parentUrlParts = window.parent.location.href.split('?'), - parentQueryParam = getQueryObject(pathParts[1]); - - if(pathParts[0]) { - parentQueryParam[PATH_PARAM_NAME] = '/#/' + pathParts[0]; - } - - path = getQueryString(parentQueryParam); - window.parent.history.replaceState( - null, - null, - path ? '%@?%@'.fmt(parentUrlParts[0], path) : parentUrlParts[0] - ); -} - -function scheduleChangeHandler(arguments) { - setTimeout(onPathChange, 100); -} - -function setConfigs(parameters) { - var host = window.location.protocol + - "//" + - window.location.hostname + - (window.location.port ? ':' + window.location.port: ''), - urlParts = location.pathname.split('/'), - resourcesPrefix = 'api/v1/views/%@/versions/%@/instances/%@/resources/'.fmt( - urlParts[2], - urlParts[3], - urlParts[4] - ); - - parameters = parameters || {}; - - $.extend(true, App.Configs, { - envDefaults: { - isStandalone: false, - timelineBaseUrl: host, - RMWebUrl: host, - yarnProtocol: parameters["yarn.protocol"] - }, - restNamespace: { - timeline: '%@atsproxy/ws/v1/timeline'.fmt(resourcesPrefix), - applicationHistory: '%@atsproxy/ws/v1/applicationhistory'.fmt(resourcesPrefix), - - aminfo: '%@rmproxy/proxy/__app_id__/ws/v1/tez'.fmt(resourcesPrefix), - aminfoV2: '%@rmproxy/proxy/__app_id__/ws/v2/tez'.fmt(resourcesPrefix), - cluster: '%@rmproxy/ws/v1/cluster'.fmt(resourcesPrefix) - }, - otherNamespace: { - cluster: '%@rmredirect/cluster'.fmt(resourcesPrefix) - } - }); - - App.TimelineRESTAdapter.reopen({ - namespace: App.Configs.restNamespace.timeline - }); - - App.advanceReadiness(); -} - -function loadParams() { - getStatus().always(function(status) { - status = status || {}; - setConfigs(status.parameters); - }); -} - -if(!redirectionCheck()) { - App.ApplicationRoute.reopen({ - actions: { - didTransition: scheduleChangeHandler, - queryParamsDidChange: scheduleChangeHandler - } - }); - - allowFullScreen(); - loadParams(); -}
