spark.vm.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // Licensed to Cloudera, Inc. under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. Cloudera, Inc. licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. function sparkViewModel() {
  17. var self = this;
  18. self.appNames = ko.observableArray(); // List of jars
  19. self.selectedAppName = ko.observable(0);
  20. self.autoContext = ko.observable(true);
  21. self.contexts = ko.observableArray(); // List of contexts
  22. self.selectedContext = ko.observable(0);
  23. self.classPath = ko.observable('');
  24. self.autoContext.forEditing = ko.computed({
  25. read: function() {
  26. return this.autoContext().toString();
  27. },
  28. write: function(newValue) {
  29. this.autoContext(newValue === "true");
  30. },
  31. owner: this
  32. });
  33. self.query = ko.mapping.fromJS({
  34. 'id': -1,
  35. 'jobId': null,
  36. 'name': null,
  37. 'description': null,
  38. 'errors': [],
  39. 'appName': '',
  40. 'classPath': '',
  41. 'context': '',
  42. 'autoContext': true,
  43. 'params': [],
  44. });
  45. self.rows = ko.observableArray();
  46. self.resultsEmpty = ko.observable(false);
  47. self.appName = ko.computed({
  48. 'read': function() {
  49. if (self.appNames().length > 0) {
  50. return self.appNames()[self.selectedAppName()];
  51. } else {
  52. return null;
  53. }
  54. },
  55. 'write': function(value) {
  56. var filtered = $.each(self.appNames(), function(index, appName) {
  57. if (appName.name() == value) {
  58. self.selectedAppName(index);
  59. }
  60. });
  61. }
  62. });
  63. self.context = ko.computed({
  64. 'read': function() {
  65. if (self.contexts().length > 0) {
  66. return self.contexts()[self.selectedContext()];
  67. } else {
  68. return null;
  69. }
  70. },
  71. 'write': function(value) {
  72. var filtered = $.each(self.contexts(), function(index, context) {
  73. if (context.name() == value) {
  74. self.selectedContext(index);
  75. }
  76. });
  77. }
  78. });
  79. self.updateResults = function(results) {
  80. self.rows.removeAll();
  81. var newRows = [];
  82. // Is a list of map
  83. if ($.inArray($.type(results), ['array', 'object']) != -1) {
  84. $.each(results, function(key, value) {
  85. newRows.push([key, value]);
  86. });
  87. } else {
  88. newRows.push([0, results]);
  89. }
  90. self.rows(newRows);
  91. };
  92. self.updateAppNames = function(appNames) {
  93. var newAppNames = [];
  94. $.each(appNames, function(key, value) {
  95. newAppNames.push({
  96. 'name': ko.observable(key),
  97. 'nice_name': ko.observable(key)
  98. });
  99. });
  100. self.appNames(newAppNames);
  101. var last = newAppNames.length > 0 ? newAppNames[0].name() : null;
  102. if (last) {
  103. self.appName(last);
  104. }
  105. };
  106. self.updateContexts = function(contexts) {
  107. var newContexts = [];
  108. $.each(contexts, function(index, value) {
  109. newContexts.push(createDropdownItem(value));
  110. });
  111. self.contexts(newContexts);
  112. var last = newContexts.length > 0 ? newContexts[0].name() : null;
  113. if (last) {
  114. self.context(last);
  115. }
  116. };
  117. self.addParam = function() {
  118. self.query.params.push({name: "", value: ""});
  119. };
  120. self.removeParam = function() {
  121. self.query.params.remove(this);
  122. };
  123. function createDropdownItem(item) {
  124. return {
  125. 'name': ko.observable(item),
  126. 'nice_name': ko.observable(item)
  127. };
  128. };
  129. self.loadDesign = function(design) {
  130. self.query.id(design.id);
  131. self.query.name(design.name);
  132. self.query.description(design.desc);
  133. self.query.appName(design.appName);
  134. self.query.classPath(design.classPath);
  135. self.query.autoContext(design.autoContext);
  136. self.query.params(design.params);
  137. self.appName(design.appName);
  138. self.chooseAppName(design.appName);
  139. self.autoContext(design.autoContext);
  140. self.context(design.context);
  141. self.chooseContext(design.context);
  142. self.classPath(design.classPath);
  143. };
  144. self.chooseAppName = function(value, e) {
  145. $.each(self.appNames(), function(index, appName) {
  146. if (appName.name() == value.name()) {
  147. self.selectedAppName(index);
  148. }
  149. });
  150. };
  151. self.chooseContext = function(value, e) {
  152. $.each(self.contexts(), function(index, context) {
  153. if (context.name() == value.name()) {
  154. self.selectedContext(index);
  155. }
  156. });
  157. };
  158. var error_fn = function(jqXHR, status, errorThrown) {
  159. try {
  160. $(document).trigger('server.error', $.parseJSON(jqXHR.responseText));
  161. } catch(e) {
  162. $(document).trigger('server.unmanageable_error', jqXHR.responseText);
  163. }
  164. };
  165. self.saveQuery = function() {
  166. var self = this;
  167. if (self.query.name()) {
  168. var data = ko.mapping.toJS(self.query);
  169. data['saveform-name'] = data['name'];
  170. data['saveform-desc'] = data['description'];
  171. data['query-appName'] = self.appName().name;
  172. data['query-classPath'] = self.classPath();
  173. data['query-autoContext'] = self.autoContext();
  174. data['query-context'] = self.context().name;
  175. data['query-params'] = JSON.stringify(self.query.params());
  176. var url = '/spark/api/save_query/';
  177. if (self.query.id() && self.query.id() != -1) {
  178. url += self.query.id() + '/';
  179. }
  180. var request = {
  181. url: url,
  182. dataType: 'json',
  183. type: 'POST',
  184. success: function(data) {
  185. if (data.status == 0) {
  186. $(document).trigger('saved.query', data);
  187. } else {
  188. self.query.errors.push(data.message);
  189. }
  190. },
  191. error: function() {
  192. $(document).trigger('error.query');
  193. },
  194. data: data
  195. };
  196. $.ajax(request);
  197. }
  198. };
  199. self.executeQuery = function() {
  200. var data = ko.mapping.toJS(self.query);
  201. data.appName = self.appName().name;
  202. data.classPath = self.classPath();
  203. data.autoContext = self.autoContext();
  204. data.context = self.context() ? self.context().name : '';
  205. data.params = JSON.stringify(self.query.params());
  206. var request = {
  207. url: '/spark/api/execute',
  208. dataType: 'json',
  209. type: 'POST',
  210. success: function(data) {
  211. self.query.errors.removeAll();
  212. self.rows.removeAll();
  213. if (data.status == 0) {
  214. $(document).trigger('execute.query', data);
  215. self.query.id(data.design);
  216. self.query.jobId(data.results.result.jobId);
  217. window.location.hash = 'jobId=' + data.results.result.jobId;
  218. self.query.context(data.results.result.context);
  219. self.checkQueryStatus();
  220. } else {
  221. self.query.errors.push(data.message);
  222. }
  223. },
  224. error: error_fn,
  225. data: data
  226. };
  227. $.ajax(request);
  228. };
  229. self.checkQueryStatus = function() {
  230. var timerId = 0;
  231. var request = {
  232. url: '/spark/api/job/' + self.query.jobId(),
  233. dataType: 'json',
  234. type: 'GET',
  235. success: function(data) {
  236. // Script finished
  237. if (data.results.status == 'OK' || data.results.status == 'ERROR') {
  238. clearInterval(timerId);
  239. self.updateResults(data.results.result);
  240. self.resultsEmpty($.isEmptyObject(data.results.result));
  241. $(document).trigger('executed.query', data);
  242. }
  243. },
  244. error: error_fn
  245. };
  246. timerId = setInterval(function(){
  247. $.ajax(request);
  248. }, 1000);
  249. };
  250. self.openQuery = function(jobId) {
  251. self.query.jobId(jobId);
  252. $(document).trigger('execute.query');
  253. self.checkQueryStatus();
  254. };
  255. self.fetchAppNames = function() {
  256. var request = {
  257. url: '/spark/api/jars',
  258. dataType: 'json',
  259. type: 'GET',
  260. success: function(data) {
  261. self.updateAppNames(data.jars);
  262. },
  263. error: error_fn
  264. };
  265. $.ajax(request);
  266. };
  267. self.fetchContexts = function() {
  268. var request = {
  269. url: '/spark/api/contexts',
  270. dataType: 'json',
  271. type: 'GET',
  272. success: function(data) {
  273. self.updateContexts(data.contexts);
  274. },
  275. error: error_fn
  276. };
  277. $.ajax(request);
  278. };
  279. self.createContext = function() {
  280. var data = $("#createContextForm").serialize(); // Not koified
  281. $("#createContextBtn").attr("data-loading-text", $("#createContextBtn").text() + " ...");
  282. $("#createContextBtn").button("loading");
  283. var request = {
  284. url: '/spark/api/create_context',
  285. dataType: 'json',
  286. type: 'POST',
  287. success: function(result) {
  288. self.query.errors.removeAll();
  289. if (result.status == 'OK') {
  290. self.contexts.push(createDropdownItem(result.name));
  291. self.context(result.name);
  292. self.autoContext(false);
  293. $(document).trigger('created.context', data);
  294. } else {
  295. $(document).trigger('error', result.result);
  296. }
  297. },
  298. error: error_fn,
  299. data: data
  300. };
  301. $.ajax(request);
  302. };
  303. }