Advertisement
Guest User

Untitled

a guest
May 22nd, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.57 KB | None | 0 0
  1. // Copyright (C) 2010-2017 GRNET S.A.
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15.  
  16. ;(function(root){
  17.  
  18. // root
  19. var root = root;
  20.  
  21. // setup namepsaces
  22. var snf = root.synnefo = root.synnefo || {};
  23. var models = snf.models = snf.models || {}
  24. var storage = snf.storage = snf.storage || {};
  25. var ui = snf.ui = snf.ui || {};
  26.  
  27. var views = snf.views = snf.views || {}
  28.  
  29. // shortcuts
  30. var bb = root.Backbone;
  31. var util = snf.util;
  32.  
  33. // generic details overlay view.
  34. views.DetailsView = views.Overlay.extend({
  35. view_id: "details_view",
  36.  
  37. content_selector: "#details-overlay",
  38. css_class: 'overlay-api-info overlay-info',
  39. overlay_id: "overlay-details",
  40.  
  41. subtitle: "",
  42. title: "Details",
  43.  
  44. show: function(title, msg, content) {
  45. this.title = title;
  46. this.msg = msg;
  47. this.content = content;
  48. views.DetailsView.__super__.show.apply(this);
  49. },
  50.  
  51. beforeOpen: function() {
  52. this.set_title(this.title);
  53. if (!this.msg) {
  54. this.$(".description.intro").hide()
  55. } else {
  56. this.$(".description.intro").html(this.msg).show();
  57. }
  58.  
  59. if (!this.content) {
  60. this.$(".description.subinfo").hide()
  61. } else {
  62. this.$(".description.subinfo").html(this.content).show();
  63. };
  64. }
  65.  
  66. });
  67.  
  68. views.SuspendedVMView = views.FeedbackView.extend({
  69. view_id: "suspended_info_view",
  70.  
  71. css_class: 'overlay-api-info overlay-error non-critical',
  72. overlay_id: "overlay-api-info",
  73.  
  74. subtitle: "",
  75. title: "VM Suspended",
  76.  
  77. beforeOpen: function() {
  78. views.SuspendedVMView.__super__.beforeOpen.apply(this);
  79. $(this.$(".form-field label")[0]).html($("#suspended-vm-overlay .description").html())
  80. },
  81.  
  82. show: function(vm, data, collect_data, extra_data, cb) {
  83. this.vm = vm;
  84. data = "Suspended VM Details";
  85. data += "\n====================";
  86. data += "\nID: " + vm.id;
  87. data += "\nName: " + vm.get('name');
  88. var public_ips = vm.get_public_ips();
  89. _.each(public_ips, function(ip) {
  90. data += "\nPublic IP{0}: {1}".format(ip.get('type'), ip.get('ip_address'));
  91. });
  92. data += "\n\n";
  93. views.SuspendedVMView.__super__.show.call(this, data, collect_data, extra_data, cb);
  94. }
  95.  
  96. });
  97.  
  98. views.ApiInfoView = views.Overlay.extend({
  99. view_id: "api_info_view",
  100.  
  101. content_selector: "#api-info-overlay",
  102. css_class: 'overlay-api-info overlay-info',
  103. overlay_id: "overlay-api-info",
  104.  
  105. subtitle: "",
  106. title: "API Access",
  107.  
  108. beforeOpen: function() {
  109. var cont = this.$(".copy-content p");
  110. var token = snf.user.get_token();
  111.  
  112. cont.html("");
  113. cont.text(token);
  114.  
  115. this.cont = cont;
  116. this.token = token;
  117. try { delete this.clip; } catch (err) {};
  118. },
  119.  
  120. onOpen: function() {
  121. views.ApiInfoView.__super__.onOpen(this, arguments);
  122. this.clip = new snf.util.ClipHelper(this.cont.parent(), this.token);
  123. },
  124.  
  125. onClose: function() {
  126. var cont = this.$(".copy-content p");
  127. var token = snf.user.token;
  128. cont.html("");
  129. }
  130. });
  131.  
  132. // TODO: implement me
  133. views.NoticeView = views.Overlay.extend({});
  134.  
  135. views.MultipleActionsView = views.View.extend({
  136. view_id: "multiple_actions",
  137.  
  138. _actions: {},
  139. el: '#multiple_actions_container',
  140.  
  141. initialize: function() {
  142.  
  143. this.actions = {};
  144. this.ns_config = {};
  145.  
  146. views.MultipleActionsView.__super__.initialize.call(this);
  147.  
  148. this.ns_tpl = this.$(".confirm_multiple_actions-template").clone()
  149.  
  150. this.init_handlers();
  151. this.update_layout();
  152.  
  153. // for heavy resize/scroll window events
  154. // do it `like a boss`
  155. this.fix_position = _.throttle(this.fix_position, 100);
  156. this.update_layout = _.throttle(this.update_layout, 100);
  157. this.show_limit = 1;
  158.  
  159. this.init_ns("vms", {
  160. msg_tpl:"Your actions will affect 1 machine",
  161. msg_tpl_plural:"Your actions will affect {0} machines",
  162. actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
  163. limit: 1,
  164. cancel_all: function() { snf.storage.vms.reset_pending_actions(); },
  165. do_all: function() { snf.storage.vms.do_all_pending_actions(); }
  166. });
  167.  
  168. this.init_ns("nets", {
  169. msg_tpl:"Your actions will affect 1 private network",
  170. msg_tpl_plural:"Your actions will affect {0} private networks",
  171. actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
  172. limit: 1,
  173. cancel_all: function(actions, config) {
  174. _.each(actions, function(action, id) {
  175. action.model.actions.reset_pending();
  176. });
  177. },
  178. do_all: function(actions, config) {
  179. _.each(actions, function(action, id) {
  180. var action_method = "do_{0}".format(action.actions[0]);
  181. action.model[action_method].apply(action.model);
  182. });
  183. }
  184. });
  185.  
  186. this.init_ns("reboots", {
  187. msg_tpl:"1 machine needs to be rebooted for changes to apply.",
  188. msg_tpl_plural:"{0} machines needs to be rebooted for changes to apply.",
  189. actions_msg: {confirm: "Reboot all", cancel: "Cancel all"},
  190. limit: 0,
  191. cancel_all: function() { snf.storage.vms.reset_reboot_required(); },
  192. do_all: function() { snf.storage.vms.do_all_reboots(); }
  193. });
  194.  
  195. this.init_ns("ips", {
  196. msg_tpl:"Your actions will affect 1 IP address.",
  197. msg_tpl_plural:"{0} actions will affect {0} IP addresses.",
  198. actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
  199. limit: 1,
  200. cancel_all: function(actions, config) {
  201. _.each(actions, function(action, id) {
  202. action.model.actions.reset_pending();
  203. });
  204. },
  205. do_all: function(actions, config) {
  206. _.each(actions, function(action, id) {
  207. var action_method = "do_{0}".format(action.actions[0]);
  208. action.model[action_method].apply(action.model);
  209. });
  210. }
  211. });
  212.  
  213. this.init_ns("volumes", {
  214. msg_tpl:"Your actions will affect 1 Volume.",
  215. msg_tpl_plural:"{0} actions will affect {0} Volumes.",
  216. actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
  217. limit: 1,
  218. cancel_all: function(actions, config) {
  219. _.each(actions, function(action, id) {
  220. action.model.actions.reset_pending();
  221. });
  222. },
  223. do_all: function(actions, config) {
  224. _.each(actions, function(action, id) {
  225. var action_method = "do_{0}".format(action.actions[0]);
  226. action.model[action_method].apply(action.model);
  227. });
  228. }
  229. });
  230.  
  231. this.init_ns("keys", {
  232. msg_tpl:"Your actions will affect 1 public key.",
  233. msg_tpl_plural:"{0} actions will affect {0} public keys.",
  234. actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
  235. limit: 1,
  236. cancel_all: function(actions, config) {
  237. _.each(actions, function(action, id) {
  238. action.model.actions.reset_pending();
  239. });
  240. },
  241. do_all: function(actions, config) {
  242. _.each(actions, function(action, id) {
  243. var action_method = "do_{0}".format(action.actions[0]);
  244. action.model[action_method].apply(action.model);
  245. });
  246. }
  247.  
  248. });
  249. },
  250.  
  251. init_ns: function(ns, params) {
  252. this.actions[ns] = {};
  253. var nsconf = this.ns_config[ns] = params || {};
  254. nsconf.cont = $(this.$("#conirm_multiple_cont_template").clone());
  255. nsconf.cont.attr("id", "confirm_multiple_cont_" + ns);
  256. $(this.el).find(".ns-confirms-cont").append(nsconf.cont).addClass(ns);
  257. $(this.el).find(".ns-confirms-cont").append(nsconf.cont).addClass("confirm-ns");
  258. nsconf.cont.find(".msg button.yes").text(
  259. nsconf.actions_msg.confirm).click(_.bind(this.do_all, this, ns));
  260. nsconf.cont.find(".msg button.no").text(
  261. nsconf.actions_msg.cancel).click(_.bind(this.cancel_all, this, ns));
  262. },
  263.  
  264. do_all: function(ns) {
  265. this.ns_config[ns].do_all.apply(this, [this.actions[ns], this.ns_config[ns]]);
  266. },
  267.  
  268. cancel_all: function(ns) {
  269. this.ns_config[ns].cancel_all.apply(this, [this.actions[ns], this.ns_config[ns]]);
  270. },
  271.  
  272. register_actions_ns: function(store, ns) {
  273. store.bind("action:set-pending", function(action, actions, model) {
  274. this.handle_action_add(ns, model, [action]);
  275. }, this);
  276. store.bind("action:unset-pending", function(action, actions, model) {
  277. this.handle_action_remove(ns, model, action);
  278. }, this);
  279. store.bind("action:reset-pending", function(actions, model) {
  280. _.each(actions.actions, function(action) {
  281. this.handle_action_remove(ns, model, action);
  282. }, this);
  283. }, this);
  284. },
  285.  
  286. init_handlers: function() {
  287. var self = this;
  288.  
  289. $(window).resize(_.bind(function(){
  290. this.fix_position();
  291. }, this));
  292.  
  293. $(window).scroll(_.bind(function(){
  294. this.fix_position();
  295. }, this));
  296.  
  297. storage.vms.bind("change:pending_action",
  298. _.bind(this.handle_action_add, this, "vms"));
  299. storage.vms.bind("change:reboot_required",
  300. _.bind(this.handle_action_add, this, "reboots"));
  301.  
  302. var ns_map = {
  303. 'ips': storage.floating_ips,
  304. 'keys': storage.keys,
  305. 'volumes': storage.volumes,
  306. 'nets': storage.networks
  307. }
  308. _.each(ns_map, function(store, ns) {
  309. this.register_actions_ns(store, ns);
  310. }, this);
  311. },
  312.  
  313. handle_action_remove: function(type, model, action) {
  314. var actions = this.actions[type];
  315. var model_actions = actions[model.id] && actions[model.id].actions;
  316. if (!model_actions) { return }
  317. actions[model.id].actions = _.without(model_actions, action);
  318. if (actions[model.id].actions.length == 0) {
  319. delete actions[model.id];
  320. }
  321. this.update_layout();
  322. },
  323.  
  324. handle_action_add: function(type, model, action) {
  325. var actions = this.actions[type];
  326.  
  327. if (type == "keys") {
  328. actions[model.id] = {model: model, actions: action};
  329. }
  330.  
  331. if (type == "ips") {
  332. actions[model.id] = {model: model, actions: action};
  333. }
  334.  
  335. if (type == "volumes") {
  336. actions[model.id] = {model: model, actions: action};
  337. }
  338.  
  339. if (type == "nets") {
  340. actions[model.id] = {model: model, actions: action};
  341. }
  342.  
  343. if (type == "vms") {
  344. _.each(actions, function(action) {
  345. if (action.model.id == model.id) {
  346. delete actions[action]
  347. }
  348. });
  349.  
  350. var actobject = {};
  351. actobject[action] = [[]];
  352. actions[model.id] = {model: model, actions: actobject};
  353. if (typeof action == "undefined") {
  354. delete actions[model.id]
  355. }
  356. }
  357.  
  358. if (type == "reboots") {
  359. _.each(actions, function(action) {
  360. if (action.model.id == model.id) {
  361. delete actions[action]
  362. }
  363. });
  364. var actobject = {};
  365. actobject['reboot'] = [[]];
  366. actions[model.id] = {model: model, actions: actobject};
  367. if (!action) {
  368. delete actions[model.id]
  369. }
  370. }
  371.  
  372. this.update_layout();
  373. },
  374.  
  375. update_actions_content: function(ns) {
  376. var conf = this.ns_config[ns];
  377. conf.cont.find(".details").empty();
  378. conf.cont.find(".msg p").text("");
  379.  
  380. var count = 0;
  381. var actionscount = 0;
  382. _.each(this.actions[ns], function(actions, model_id) {
  383. count++;
  384. _.each(actions.actions, function(params, act_name){
  385. if (_.isString(params)) {
  386. actionscount++;
  387. return
  388. }
  389. if (params && params.length) {
  390. actionscount += params.length;
  391. } else {
  392. actionscount++;
  393. }
  394. })
  395. this.total_confirm_actions++;
  396. });
  397.  
  398. var limit = conf.limit;
  399. if (ui.main.current_view.view_id == "vm_list") {
  400. limit = 0;
  401. }
  402.  
  403. if (actionscount > limit) {
  404. conf.cont.show();
  405. this.confirm_ns_open++;
  406. } else {
  407. conf.cont.hide();
  408. }
  409.  
  410. var msg = count > 1 ? conf.msg_tpl_plural : conf.msg_tpl;
  411. conf.cont.find(".msg p").text(msg.format(count));
  412.  
  413. return conf.cont;
  414. },
  415.  
  416. fix_position: function() {
  417. $('.confirm_multiple').removeClass('fixed');
  418. if (($(this.el).offset().top +$(this.el).height())> ($(window).scrollTop() + $(window).height())) {
  419. $('.confirm_multiple').addClass('fixed');
  420. }
  421. },
  422.  
  423. update_layout: function() {
  424. this.confirm_ns_open = 0;
  425. this.total_confirm_actions = 0;
  426.  
  427. $(this.el).show();
  428. $(this.el).find("#conirm_multiple_cont_template").hide();
  429. $(this.el).find(".confirm-ns").show();
  430.  
  431. _.each(this.ns_config, _.bind(function(params, key) {
  432. this.update_actions_content(key);
  433. }, this));
  434.  
  435. if (this.confirm_ns_open > 0) {
  436. $(this.el).show();
  437. this.$(".confirm-all-cont").hide();
  438. this.$(".ns-confirms-cont").show();
  439. } else {
  440. $(this.el).hide();
  441. this.$(".confirm-all-cont").hide();
  442. this.$(".ns-confirms-cont").hide();
  443. }
  444.  
  445. $(window).trigger("resize");
  446. }
  447. })
  448.  
  449. // menu wrapper view
  450. views.SelectView = views.View.extend({
  451.  
  452. initialize: function(view, router) {
  453. this.parent = view;
  454. this.router = router;
  455. this.pane_view_selector = $(".css-tabs");
  456. this.machine_view_selector = $("#view-select");
  457. this.el = $(".css-tabs");
  458. this.title = $(".tab-name");
  459.  
  460. this.set_handlers();
  461. this.update_layout();
  462.  
  463. views.SelectView.__super__.initialize.apply(this, arguments);
  464. },
  465.  
  466. clear_active: function() {
  467. this.pane_view_selector.find("a").removeClass("active");
  468. this.machine_view_selector.find("a").removeClass("activelink");
  469. },
  470.  
  471. // intercept menu links
  472. set_handlers: function() {
  473. var self = this;
  474. this.pane_view_selector.find("a").hover(function(){
  475. self.title.text($(this).data("hover-title"));
  476. }, function(){
  477. self.title.text(self.parent.get_title());
  478. });
  479.  
  480. this.pane_view_selector.find("a#machines_view_link").click(
  481. _.bind(function(ev){
  482. ev.preventDefault();
  483. this.router.vms_index();
  484. }, this)
  485. );
  486.  
  487. this.pane_view_selector.find("a#networks_view_link").click(
  488. _.bind(function(ev){
  489. ev.preventDefault();
  490. this.router.networks_view();
  491. }, this)
  492. );
  493.  
  494. this.pane_view_selector.find("a#ips_view_link").click(
  495. _.bind(function(ev){
  496. ev.preventDefault();
  497. this.router.ips_view();
  498. }, this)
  499. );
  500.  
  501. this.machine_view_selector.find("a#volumes_view_list_link").click(
  502. _.bind(function(ev){
  503. ev.preventDefault();
  504. this.router.volumes_view();
  505. }, this)
  506. );
  507.  
  508. this.pane_view_selector.find("a#public_keys_view_link").click(
  509. _.bind(function(ev){
  510. ev.preventDefault();
  511. this.router.public_keys_view();
  512. }, this)
  513. );
  514.  
  515. this.machine_view_selector.find("a#machines_view_icon_link").click(
  516. _.bind(function(ev){
  517. ev.preventDefault();
  518. var d = $.now();
  519. this.router.vms_icon_view();
  520. }, this)
  521. );
  522.  
  523. this.machine_view_selector.find("a#machines_view_list_link").click(
  524. _.bind(function(ev){
  525. ev.preventDefault();
  526. this.router.vms_list_view();
  527. }, this)
  528. );
  529.  
  530. var selector = "a#machines_view_single_link"
  531. this.machine_view_selector.find(selector).click(
  532. _.bind(function(ev){
  533. ev.preventDefault();
  534. this.router.vms_single_view();
  535. }, this)
  536. );
  537. },
  538.  
  539. update_layout: function() {
  540. this.clear_active();
  541.  
  542. var pane_index = this.parent.pane_ids[this.parent.current_view_id];
  543. $(this.pane_view_selector.find("a")).removeClass("active");
  544. $(this.pane_view_selector.find("a").get(pane_index)).addClass("active");
  545.  
  546. if (this.parent.current_view && this.parent.current_view.vms_view) {
  547.  
  548. if (storage.vms.no_ghost_vms().length > 0) {
  549. this.machine_view_selector.show();
  550. var machine_index = this.parent.views_ids[this.parent.current_view_id];
  551. $(this.machine_view_selector.find("a").get(machine_index)).addClass("activelink");
  552. } else {
  553. this.machine_view_selector.hide();
  554. }
  555. } else {
  556. this.machine_view_selector.hide();
  557. }
  558.  
  559. }
  560. });
  561.  
  562. views.MainView = views.View.extend({
  563. el: 'body',
  564. view_id: 'main',
  565.  
  566. // FIXME: titles belong to SelectView
  567. views_titles: {
  568. 'icon': 'machines', 'single': 'machines',
  569. 'list': 'machines', 'networks': 'networks',
  570. 'ips': 'IP addresses',
  571. 'volumes': 'disks',
  572. 'public-keys': 'public keys'
  573. },
  574.  
  575. // indexes registry
  576. views_indexes: {
  577. 0: 'icon',
  578. 2: 'single',
  579. 1: 'list',
  580. 3: 'networks',
  581. 4: 'ips',
  582. 5: 'volumes',
  583. 6: 'public-keys'
  584. },
  585.  
  586. views_pane_indexes: {
  587. 0: 'single',
  588. 1: 'networks',
  589. 2: 'ips',
  590. 3: 'volumes',
  591. 4: 'public-keys'
  592. },
  593.  
  594. // views classes registry
  595. views_classes: {
  596. 'icon': views.IconView,
  597. 'single': views.SingleView,
  598. 'list': views.ListView,
  599. 'networks': views.NetworksPaneView,
  600. 'ips': views.IpsPaneView,
  601. 'volumes': views.VolumesPaneView,
  602. 'public-keys': views.PublicKeysPaneView
  603. },
  604.  
  605. // view ids
  606. views_ids: {
  607. 'icon': 0,
  608. 'single': 2,
  609. 'list': 1,
  610. 'networks': 3,
  611. 'ips': 4,
  612. 'volumes': 5,
  613. 'public-keys': 6
  614. },
  615.  
  616. // on which pane id each view exists
  617. // machine views (icon,single,list) are all on first pane
  618. pane_ids: {
  619. 'icon': 0,
  620. 'single': 0,
  621. 'list': 0,
  622. 'volumes': 1,
  623. 'networks': 2,
  624. 'ips': 3,
  625. 'public-keys': 4
  626. },
  627.  
  628. initialize: function(show_view) {
  629. if (!show_view) { show_view = 'icon' };
  630.  
  631. this.router = snf.router;
  632. this.empty_hidden = true;
  633. // fallback to browser error reporting (true for debug)
  634. this.skip_errors = true
  635.  
  636. // reset views
  637. this.views = {};
  638.  
  639. this.el = $("#app");
  640. // reset main view status
  641. this._loaded = false;
  642. this.status = "Initializing...";
  643.  
  644. // initialize handlers
  645. this.init_handlers();
  646.  
  647. // identify initial view from user cookies
  648. // this view will be visible after loading of
  649. // main view
  650. this.initial_view = this.session_view();
  651.  
  652. views.MainView.__super__.initialize.call(this);
  653.  
  654. $(window).focus(_.bind(this.handle_window_focus, this, "focus"));
  655. $(window).blur(_.bind(this.handle_window_focus, this, "out"));
  656.  
  657. this.focused = true;
  658. },
  659.  
  660. handle_window_focus: function(focus) {
  661. if (!snf.config.delay_on_blur) { return };
  662.  
  663. if (focus === "focus") {
  664. this.focused = true;
  665. this.set_interval_timeouts();
  666. } else {
  667. this.focused = false;
  668. this.set_interval_timeouts();
  669. }
  670. },
  671.  
  672. set_interval_timeouts: function(time) {
  673. _.each(this._fetchers, _.bind(function(fetcher){
  674. if (!fetcher) { return };
  675. if (this.focused) {
  676. fetcher.interval = fetcher.normal_interval;
  677. fetcher.stop(false).start(true);
  678. } else {
  679. fetcher.interval = fetcher.maximum_interval;
  680. fetcher.stop(false).start(false);
  681. }
  682.  
  683. }, this));
  684. },
  685.  
  686. vms_handlers_registered: false,
  687.  
  688. // register event handlers
  689. //
  690. // vms storage events to identify if vms list
  691. // is empty and display empty view if user viewing
  692. // a machine view
  693. //
  694. // api/ui error event handlers
  695. init_handlers: function() {
  696. // vm handlers
  697. storage.vms.bind("remove", _.bind(this.check_empty, this));
  698. storage.vms.bind("add", _.bind(this.check_empty, this));
  699. storage.vms.bind("change:status", _.bind(this.check_empty, this));
  700. storage.vms.bind("reset", _.bind(this.check_empty, this));
  701. storage.quotas.bind("change", _.bind(this.update_create_buttons_status, this));
  702. // additionally check quotas the first time they get fetched
  703. storage.quotas.bind("add", _.bind(this.update_create_buttons_status, this));
  704.  
  705. },
  706.  
  707. handle_api_error_state: function(state) {
  708. if (snf.api.error_state === snf.api.STATES.ERROR) {
  709. this.stop_intervals();
  710. } else {
  711. if (this.intervals_stopped) {
  712. this.update_intervals();
  713. }
  714. }
  715. },
  716.  
  717. handle_api_error: function(args) {
  718. if (arguments.length == 1) { arguments = _.toArray(arguments[0])};
  719.  
  720. if (!_.last(arguments).display) {
  721. return;
  722. }
  723.  
  724. this.error_state = true;
  725.  
  726. var xhr = arguments[0];
  727. var args = util.parse_api_error.apply(util, arguments);
  728.  
  729. // force logout if UNAUTHORIZED request arrives
  730. if (args.code == 401) { snf.auth_client.redirect_to_login(); return };
  731.  
  732. var error_entry = [args.ns, args.code, args.message,
  733. args.api_message, args.type,
  734. args.details, args];
  735. this.error_view.show_error.apply(this.error_view, error_entry);
  736. },
  737.  
  738. handle_ui_error: function(data) {
  739. var msg = data.msg, code = data.code, err_obj = data.error;
  740. error = msg + "<br /><br />" + snf.util.stacktrace().replace("at", "<br /><br />at");
  741. params = { title: "UI error", extra_details: data.extra };
  742. delete data.extra.allow_close;
  743. params.allow_close = data.extra.allow_close === undefined ? true : data.extra.allow_close;
  744. this.error_view.show_error("UI", -1, msg, undefined,
  745. "JS Exception", error, params);
  746. },
  747.  
  748. init_overlays: function() {
  749. this.create_vm_view = new views.VMCreateView();
  750. this.create_snapshot_view = new views.SnapshotCreateView();
  751. this.api_info_view = new views.ApiInfoView();
  752. this.details_view = new views.DetailsView();
  753. this.suspended_view = new views.SuspendedVMView();
  754. //this.notice_view = new views.NoticeView();
  755. },
  756.  
  757. show_loading_view: function() {
  758. $("#container #content").hide();
  759. $("#loading-view").show();
  760. },
  761.  
  762. hide_loading_view: function() {
  763. $("#container #content").show();
  764. $("#loading-view").hide();
  765. $(".css-panes").show();
  766. },
  767.  
  768. items_to_load: 8,
  769. completed_items: 0,
  770. check_status: function(loaded) {
  771. this.completed_items++;
  772. // images, flavors loaded
  773. if (this.completed_items == this.items_to_load) {
  774. this.update_status("layout", 1);
  775. var self = this;
  776. window.setTimeout(function(){
  777. self.after_load();
  778. }, 10)
  779. }
  780. },
  781.  
  782. load_missing_images: function(cb) {
  783. synnefo.storage.vms.load_missing_images(cb);
  784. },
  785.  
  786. load_nets_and_vms: function() {
  787. var self = this;
  788. this.update_status("vms", 0);
  789. storage.vms.fetch({refresh:true, update:false, success: function(){
  790. self.load_missing_images(function(){
  791. self.update_status("vms", 1);
  792. self.update_status("layout", 0);
  793. self.check_status();
  794. });
  795. }});
  796.  
  797. this.update_status("networks", 0);
  798. $.when([
  799. storage.networks.fetch({refresh: true}),
  800. storage.floating_ips.fetch({refresh: true}),
  801. storage.subnets.fetch({refresh: true}),
  802. storage.ports.fetch({refresh: true})
  803. ]).done(function() {
  804. self.update_status("networks", 1);
  805. self.check_status();
  806. })
  807. },
  808.  
  809. _fetchers: {},
  810. init_interval: function(key, collection) {
  811. if (this._fetchers[key]) { return }
  812. var fetcher_params = [snf.config.update_interval,
  813. snf.config.update_interval_increase || 500,
  814. snf.config.fast_interval || snf.config.update_interval/2,
  815. snf.config.update_interval_increase_after_calls || 4,
  816. snf.config.update_interval_max || 20000,
  817. true,
  818. {is_recurrent: true},
  819. key];
  820. var fetcher = collection.get_fetcher.apply(collection, _.clone(fetcher_params));
  821. this._fetchers[key] = fetcher;
  822. collection.fetch();
  823.  
  824. },
  825.  
  826. init_intervals: function() {
  827. _.each({
  828. 'networks': storage.networks,
  829. 'vms': storage.vms,
  830. 'quotas': storage.quotas,
  831. 'projects': storage.projects,
  832. 'ips': storage.floating_ips,
  833. 'subnets': storage.subnets,
  834. 'ports': storage.ports,
  835. 'volumes': storage.volumes,
  836. 'keys': storage.keys
  837. }, function(col, name) {
  838. this.init_interval(name, col)
  839. }, this);
  840. },
  841.  
  842. stop_intervals: function() {
  843. _.each(this._fetchers, function(fetcher) {
  844. fetcher.stop();
  845. });
  846. this.intervals_stopped = true;
  847. },
  848.  
  849. update_intervals: function() {
  850. _.each(this._fetchers, function(fetcher) {
  851. fetcher.stop();
  852. fetcher.start();
  853. })
  854. this.intervals_stopped = false;
  855. },
  856.  
  857. after_load: function() {
  858. var self = this;
  859. this.init_intervals();
  860. this.update_intervals();
  861. this.update_status("layout", 0);
  862.  
  863. // bypass update_hidden_views in initial view
  864. // rendering to force all views to get render
  865. // on their creation
  866. var uhv = snf.config.update_hidden_views;
  867. snf.config.update_hidden_views = true;
  868. this.initialize_views();
  869. snf.config.update_hidden_views = uhv;
  870.  
  871. window.setTimeout(function() {
  872. self.load_initialize_overlays();
  873. }, 20);
  874. },
  875.  
  876. load_initialize_overlays: function() {
  877. this.init_overlays();
  878. // display initial view
  879. this.loaded = true;
  880.  
  881. // application start point
  882. this.check_empty();
  883. this.show_initial_view();
  884. },
  885.  
  886. load: function() {
  887. if (synnefo.config.use_glance) {
  888. synnefo.glance.register();
  889. }
  890. this.error_view = new views.ErrorView();
  891. this.vm_resize_view = new views.VmResizeView();
  892. this.vm_reassign_view = new views.VmReassignView();
  893. this.ip_reassign_view = new views.IPReassignView();
  894. this.network_reassign_view = new views.NetworkReassignView();
  895. this.volume_reassign_view = new views.VolumeReassignView();
  896.  
  897. // api request error handling
  898. synnefo.api.bind("error", _.bind(this.handle_api_error, this));
  899. synnefo.api.bind("change:error_state", _.bind(this.handle_api_error_state, this));
  900. synnefo.ui.bind("error", _.bind(this.handle_ui_error, this));
  901.  
  902. this.feedback_view = new views.FeedbackView();
  903.  
  904. if (synnefo.config.use_glance) {
  905. this.custom_images_view = new views.CustomImagesOverlay();
  906. }
  907.  
  908. var self = this;
  909. // initialize overlay views
  910.  
  911. // display loading message
  912. this.show_loading_view();
  913. this.update_status("flavors", 0);
  914. storage.flavors.fetch({refresh:true, update:false, success:function(){
  915. self.update_status("flavors", 1);
  916. self.update_status("resources", 0);
  917. self.check_status()
  918. storage.resources.fetch({refresh:true, update:false, success: function(){
  919. self.update_status("resources", 1);
  920. self.update_status("projects", 0);
  921. self.check_status();
  922. storage.projects.fetch({refresh:true, update:true, success: function() {
  923. self.update_status("projects", 1);
  924. self.update_status("quotas", 0);
  925. self.check_status();
  926. storage.quotas.fetch({refresh:true, update:true, success: function() {
  927. self.update_status("quotas", 1);
  928. self.check_status();
  929. self.update_status("volumes", 0);
  930. storage.volume_types.fetch({refresh: true, update: false, success: function() {
  931. storage.volumes.fetch({refresh:true, update:false, success: function(){
  932. self.update_status("volumes", 1);
  933. self.check_status();
  934. }});
  935. }});
  936. // sync load initial data
  937. self.update_status("images", 0);
  938. storage.images.fetch({refresh:true, update:false, success: function(){
  939. self.update_status("images", 1);
  940. self.check_status();
  941. self.load_nets_and_vms();
  942. }});
  943. }});
  944. }})
  945. }})
  946. }})
  947. },
  948.  
  949. update_status: function(ns, state) {
  950. var el = $("#loading-view .header."+ns);
  951. if (state == 0) {
  952. el.removeClass("off").addClass("on");
  953. }
  954. if (state == 1) {
  955. el.removeClass("on").addClass("done");
  956. }
  957. },
  958.  
  959. initialize_views: function() {
  960. this.select_view = new views.SelectView(this, this.router);
  961. this.empty_view = new views.EmptyView();
  962. this.metadata_view = new views.MetadataView();
  963. this.multiple_actions_view = new views.MultipleActionsView();
  964.  
  965. this.add_view("icon");
  966. this.add_view("list");
  967. this.add_view("single");
  968. this.add_view("networks");
  969. this.add_view("ips");
  970. this.add_view("public-keys");
  971.  
  972. this.init_menu();
  973. },
  974.  
  975. init_menu: function() {
  976. $(".usermenu .feedback").click(_.bind(function(e){
  977. e.preventDefault();
  978. this.feedback_view.show();
  979. }, this));
  980. },
  981.  
  982. // initial view based on user cookie
  983. show_initial_view: function() {
  984. this.set_vm_view_handlers();
  985. this.hide_loading_view();
  986. bb.history.start();
  987. this.trigger("ready");
  988. },
  989.  
  990. show_vm_details: function(vm) {
  991. if (vm) {
  992. this.router.vm_details_view(vm.id);
  993. }
  994. },
  995.  
  996. update_create_buttons_status: function() {
  997. var vms = storage.quotas.can_create('vm');
  998. var create_button = $("#createcontainer #create");
  999. var msg = snf.config.limit_reached_msg;
  1000. if (!vms) {
  1001. create_button.addClass("disabled");
  1002. snf.util.set_tooltip(create_button, msg, {tipClass: 'warning tooltip'});
  1003. } else {
  1004. create_button.removeClass("disabled");
  1005. snf.util.unset_tooltip(create_button);
  1006. }
  1007. },
  1008.  
  1009. set_vm_view_handlers: function() {
  1010. var self = this;
  1011. $("#createcontainer #create").click(function(e){
  1012. e.preventDefault();
  1013. if ($(this).hasClass("disabled")) { return }
  1014. self.router.vm_create_view();
  1015. });
  1016. },
  1017.  
  1018. check_empty: function() {
  1019. if (!this.loaded) { return }
  1020. if (storage.vms.no_ghost_vms().length == 0) {
  1021. if (!(this.current_view instanceof synnefo.views.VMListView)) {
  1022. this.show_empty();
  1023. return;
  1024. }
  1025. this.show_view("machines");
  1026. this.router.show_welcome();
  1027. this.empty_hidden = false;
  1028. } else {
  1029. this.hide_empty();
  1030. }
  1031. },
  1032.  
  1033. show_empty: function() {
  1034. if (!this.empty_hidden) { return };
  1035. $("#machines-pane-top").addClass("empty");
  1036.  
  1037. this.$(".panes").hide();
  1038. this.$("#machines-pane").show();
  1039.  
  1040. this.hide_views([]);
  1041. this.empty_hidden = false;
  1042. this.empty_view.show();
  1043. this.select_view.update_layout();
  1044. this.empty_hidden = false;
  1045. },
  1046.  
  1047. hide_empty: function() {
  1048. if (this.empty_hidden) { return };
  1049. $("#machines-pane-top").removeClass("empty");
  1050.  
  1051. this.empty_view.hide(true);
  1052. this.router.vms_index();
  1053. this.empty_hidden = true;
  1054. this.select_view.update_layout();
  1055. },
  1056.  
  1057. get_title: function(view_id) {
  1058. var view_id = view_id || this.current_view_id;
  1059. return this.views_titles[view_id];
  1060. },
  1061.  
  1062. // return class object for the given view or false if
  1063. // the view is not registered
  1064. get_class_for_view: function (view_id) {
  1065. if (!this.views_classes[view_id]) {
  1066. return false;
  1067. }
  1068. return this.views_classes[view_id];
  1069. },
  1070.  
  1071. view: function(view_id) {
  1072. return this.views[view_id];
  1073. },
  1074.  
  1075. add_view: function(view_id) {
  1076. if (!this.views[view_id]) {
  1077. var cls = this.get_class_for_view(view_id);
  1078. if (this.skip_errors) {
  1079. this.views[view_id] = new cls();
  1080. $(this.views[view_id]).bind("resize", _.bind(function() {
  1081. window.forcePositionFooter();
  1082. this.multiple_actions_view.fix_position();
  1083. }, this));
  1084. } else {
  1085. // catch ui errors
  1086. try {
  1087. this.views[view_id] = new cls();
  1088. $(this.views[view_id]).bind("resize", _.bind(function() {
  1089. window.positionFooter();
  1090. this.multiple_actions_view.fix_position();
  1091. }, this));
  1092. } catch (err) {snf.ui.trigger_error(-1, "Cannot add view", err)}
  1093. }
  1094. } else {
  1095. }
  1096.  
  1097. if (this.views[view_id].vms_view) {
  1098. this.views[view_id].metadata_view = this.metadata_view;
  1099. }
  1100. return this.views[view_id];
  1101. },
  1102.  
  1103. hide_views: function(skip) {
  1104. _.each(this.views, function(view) {
  1105. if (skip.indexOf(view) === -1) {
  1106. view.hide();
  1107. }
  1108. }, this)
  1109. },
  1110.  
  1111. get: function(view_id) {
  1112. return this.views[view_id];
  1113. },
  1114.  
  1115. session_view: function() {
  1116. if (this.pane_view_from_session() > 0) {
  1117. return this.views_pane_indexes[this.pane_view_from_session()];
  1118. } else {
  1119. return this.views_indexes[this.machine_view_from_session()];
  1120. }
  1121. },
  1122.  
  1123. pane_view_from_session: function() {
  1124. return $.cookie("pane_view") || 0;
  1125. },
  1126.  
  1127. machine_view_from_session: function() {
  1128. return $.cookie("machine_view") || 0;
  1129. },
  1130.  
  1131. update_session: function() {
  1132. $.cookie("pane_view", this.pane_ids[this.current_view_id]);
  1133. if (this.current_view.vms_view) {
  1134. $.cookie("machine_view", this.views_ids[this.current_view_id]);
  1135. }
  1136. },
  1137.  
  1138. identify_view: function(view_id) {
  1139. // machines view_id is an alias to
  1140. // one of the 3 machines view
  1141. // identify which one (if no cookie set defaults to icon)
  1142. if (view_id == "machines") {
  1143. var index = this.machine_view_from_session();
  1144. view_id = this.views_indexes[index];
  1145. }
  1146. return view_id;
  1147. },
  1148.  
  1149. // switch to current view pane
  1150. // if differs from the visible one
  1151. show_view_pane: function() {
  1152. if (this.current_view.pane != this.current_pane) {
  1153. $(this.current_view.pane).show();
  1154. $(this.current_pane).hide();
  1155. this.current_pane = this.current_view.pane;
  1156. }
  1157. },
  1158.  
  1159. show_view: function(view_id) {
  1160. //var d = new Date;
  1161. var ret = this._show_view(view_id);
  1162. //console.log((new Date)-d)
  1163. return ret;
  1164. },
  1165.  
  1166. _show_view: function(view_id) {
  1167. // same view, visible
  1168. // get out of here asap
  1169. if (this.current_view &&
  1170. this.current_view.id == view_id &&
  1171. this.current_view.visible()) {
  1172. return;
  1173. }
  1174.  
  1175. // choose proper view_id
  1176. view_id = this.identify_view(view_id);
  1177.  
  1178. // add/create view and update current view
  1179. var view = this.add_view(view_id);
  1180.  
  1181. // set current view
  1182. this.current_view = view;
  1183. this.current_view_id = view_id;
  1184.  
  1185. // hide all other views
  1186. this.hide_views([this.current_view]);
  1187.  
  1188. // FIXME: depricated
  1189. $(".large-spinner").remove();
  1190.  
  1191. storage.vms.reset_pending_actions();
  1192. //storage.networks.reset_pending_actions();
  1193. storage.vms.stop_stats_update();
  1194.  
  1195. // show current view
  1196. this.show_view_pane();
  1197. view.show(true);
  1198.  
  1199. // update menus
  1200. if (this.select_view) {
  1201. this.select_view.update_layout();
  1202. }
  1203.  
  1204. var update_layout = this.current_view.__update_layout;
  1205. update_layout && update_layout.call(this.current_view);
  1206.  
  1207. // update cookies
  1208. this.update_session();
  1209.  
  1210. // machines view subnav
  1211. if (this.current_view.vms_view) {
  1212. $("#machines-pane").show();
  1213. } else {
  1214. $("#machines-pane").hide();
  1215. }
  1216.  
  1217. // fix footer position
  1218. // TODO: move footer handlers in
  1219. // main view (from home.html)
  1220. if (window.positionFooter) {
  1221. window.positionFooter();
  1222. }
  1223.  
  1224. // trigger view change event
  1225. this.trigger("view:change", this.current_view.view_id);
  1226. this.select_view.title.text(this.get_title());
  1227. $(window).trigger("view:change");
  1228. return view;
  1229. },
  1230.  
  1231. reset_vm_actions: function() {
  1232.  
  1233. },
  1234.  
  1235. // identify current view
  1236. // based on views element visibility
  1237. current_view_id: function() {
  1238. var found = false;
  1239. _.each(this.views, function(key, value) {
  1240. if (value.visible()) {
  1241. found = value;
  1242. }
  1243. })
  1244. return found;
  1245. }
  1246.  
  1247. });
  1248.  
  1249. snf.ui.main = new views.MainView();
  1250.  
  1251. snf.ui.init = function() {
  1252. if (snf.config.handle_window_exceptions) {
  1253. window.onerror = function(msg, file, line) {
  1254. snf.ui.trigger_error("CRITICAL", msg, {}, { file:file + ":" + line, allow_close: true });
  1255. };
  1256. }
  1257.  
  1258. if (synnefo.config.snapshots_groups.length || _.keys(synnefo.config.flavor_override_allow_create).length) {
  1259. var token_data = {
  1260. 'auth': {
  1261. 'token': {
  1262. 'id': synnefo.user.get_token()
  1263. }
  1264. }
  1265. };
  1266.  
  1267. var override_policy = synnefo.config.flavor_override_allow_create;
  1268. var allow_create_groups = _.keys(override_policy);
  1269. bb.sync('create', undefined, {
  1270. url: synnefo.config.auth_url + '/tokens',
  1271. data: JSON.stringify(token_data),
  1272. contentType: 'application/json',
  1273. success: function(data) {
  1274. if (data.access) {
  1275. _.each(data.access.user.roles, function(g) {
  1276. var group = g.name;
  1277. if (synnefo.config.snapshots_groups.indexOf(group) > -1) {
  1278. synnefo.config.snapshots_enabled = true;
  1279. }
  1280. if (allow_create_groups.length && allow_create_groups.indexOf(group) > -1) {
  1281. _.each(override_policy[group], function(flv) {
  1282. try {
  1283. synnefo.config.user_override_allow_create.push(new RegExp(flv));
  1284. } catch(err) { console.error(err); }
  1285. });
  1286. }
  1287. });
  1288. }
  1289. },
  1290. error: function() { console.error(arguments) },
  1291. complete: function() { snf.ui.main.load(); }
  1292. });
  1293. } else {
  1294. snf.ui.main.load();
  1295. }
  1296.  
  1297. }
  1298.  
  1299. })(this);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement