]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7074 SONAR-7310 SONAR-7357 SONAR-7395 refactor web api page
authorStas Vilchik <vilchiks@gmail.com>
Thu, 25 Feb 2016 18:08:22 +0000 (19:08 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Mon, 29 Feb 2016 13:13:36 +0000 (14:13 +0100)
40 files changed:
server/sonar-web/src/main/js/api/web-api.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/api-documentation/action-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/actions-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/app.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/controller.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/filters-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/header-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/item-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/layout.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/list-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/list.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/router.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/search-view.js [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-action.hbs [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-filters.hbs [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-header.hbs [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-layout.hbs [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-search.hbs [deleted file]
server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-web-service.hbs [deleted file]
server/sonar-web/src/main/js/apps/web-api/app.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/Action.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/DeprecatedBadge.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/Domain.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/InternalBadge.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/Menu.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/Params.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/ResponseExample.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/Search.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/styles/web-api.css [new file with mode: 0644]
server/sonar-web/src/main/js/apps/web-api/utils.js [new file with mode: 0644]
server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs
server/sonar-web/src/main/less/pages/api-documentation.less [deleted file]
server/sonar-web/src/main/less/sonar.less
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api_documentation_controller.rb [deleted file]
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/web_api_controller.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/config/routes.rb
server/sonar-web/webpack.config.js

diff --git a/server/sonar-web/src/main/js/api/web-api.js b/server/sonar-web/src/main/js/api/web-api.js
new file mode 100644 (file)
index 0000000..d7c2c73
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { getJSON } from '../helpers/request';
+
+export function fetchWebApi (showInternal = true) {
+  const url = '/api/webservices/list';
+  const data = { 'include_internals': showInternal };
+
+  return getJSON(url, data).then(r => r.webServices.map(domain => {
+    const internal = !domain.actions.find(action => !action.internal);
+
+    return { ...domain, internal };
+  }));
+}
+
+export function fetchResponseExample (domain, action) {
+  const url = '/api/webservices/response_example';
+  const data = { controller: domain, action };
+
+  return getJSON(url, data);
+}
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/action-view.js b/server/sonar-web/src/main/js/apps/api-documentation/action-view.js
deleted file mode 100644 (file)
index 90969fe..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import $ from 'jquery';
-import Marionette from 'backbone.marionette';
-import Template from './templates/api-documentation-action.hbs';
-
-export default Marionette.ItemView.extend({
-  className: 'panel panel-vertical',
-  template: Template,
-
-  modelEvents: {
-    'change': 'render'
-  },
-
-  events: {
-    'click .js-show-response-example': 'onShowResponseExampleClick',
-    'click .js-hide-response-example': 'onHideResponseExampleClick'
-  },
-
-  initialize () {
-    this.listenTo(this.options.state, 'change', this.toggleHidden);
-  },
-
-  onRender () {
-    this.$el.attr('data-web-service', this.model.get('path'));
-    this.$el.attr('data-action', this.model.get('key'));
-    this.toggleHidden();
-    this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' });
-  },
-
-  onShowResponseExampleClick (e) {
-    e.preventDefault();
-    this.fetchResponse();
-  },
-
-  onHideResponseExampleClick (e) {
-    e.preventDefault();
-    this.model.unset('responseExample');
-  },
-
-  fetchResponse () {
-    const url = '/api/webservices/response_example';
-    const options = { controller: this.model.get('path'), action: this.model.get('key') };
-    return $.get(url, options).done(r => {
-      this.model.set({ responseExample: r.example });
-    });
-  },
-
-  toggleHidden () {
-    const test = this.model.get('path') + '/' + this.model.get('key');
-    this.$el.toggleClass('hidden', !this.options.state.match(test, this.model.get('internal')));
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/actions-view.js b/server/sonar-web/src/main/js/apps/api-documentation/actions-view.js
deleted file mode 100644 (file)
index c403aed..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import $ from 'jquery';
-import Marionette from 'backbone.marionette';
-import ActionView from './action-view';
-
-export default Marionette.CollectionView.extend({
-  childView: ActionView,
-
-  childViewOptions () {
-    return {
-      state: this.options.state
-    };
-  },
-
-  scrollToTop () {
-    let parent = this.$el.scrollParent();
-    if (parent.is(document)) {
-      parent = $(window);
-    }
-    parent.scrollTop(0);
-  },
-
-  scrollToAction (action) {
-    const model = this.collection.findWhere({ key: action });
-    if (model != null) {
-      const view = this.children.findByModel(model);
-      if (view != null) {
-        this.scrollToView(view);
-      }
-    }
-  },
-
-  scrollToView (view) {
-    const elOffset = view.el.getBoundingClientRect();
-    if (elOffset != null) {
-      const scrollTop = elOffset.top - 70;
-      window.scrollTo(0, scrollTop);
-    }
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/app.js b/server/sonar-web/src/main/js/apps/api-documentation/app.js
deleted file mode 100644 (file)
index 7de5702..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import $ from 'jquery';
-import Backbone from 'backbone';
-import Marionette from 'backbone.marionette';
-import Router from './router';
-import Controller from './controller';
-import Layout from './layout';
-import List from './list';
-import ListView from './list-view';
-import FiltersView from './filters-view';
-import SearchView from './search-view';
-
-const App = new Marionette.Application();
-const init = function () {
-  const options = window.sonarqube;
-
-  // State
-  this.state = new Backbone.Model({ internal: false });
-  this.state.match = function (test, internal) {
-    const pattern = new RegExp(this.get('query'), 'i');
-    const internalCheck = !this.get('internal') && internal;
-    return test.search(pattern) !== -1 && !internalCheck;
-  };
-
-  // Layout
-  this.layout = new Layout({ el: options.el });
-  this.layout.render();
-  $('#footer').addClass('search-navigator-footer');
-
-  // Web Services List
-  this.list = new List();
-
-  // Controller
-  this.controller = new Controller({
-    app: this,
-    state: this.state
-  });
-
-  // List View
-  this.listView = new ListView({
-    collection: this.list,
-    state: this.state
-  });
-  this.layout.resultsRegion.show(this.listView);
-
-  // Filters View
-  this.filtersView = new FiltersView({
-    collection: this.list,
-    state: this.state
-  });
-  this.layout.actionsRegion.show(this.filtersView);
-
-  // Search View
-  this.searchView = new SearchView({
-    state: this.state
-  });
-  this.layout.searchRegion.show(this.searchView);
-
-  // Router
-  this.router = new Router({ app: this });
-  Backbone.history.start({
-    pushState: true,
-    root: options.urlRoot
-  });
-};
-
-App.on('start', function (options) {
-  init.call(App, options);
-});
-
-window.sonarqube.appStarted.then(options => App.start(options));
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/controller.js b/server/sonar-web/src/main/js/apps/api-documentation/controller.js
deleted file mode 100644 (file)
index db088e1..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import _ from 'underscore';
-import Backbone from 'backbone';
-import Marionette from 'backbone.marionette';
-import ActionsView from './actions-view';
-import HeaderView from './header-view';
-
-export default Marionette.Controller.extend({
-  initialize (options) {
-    this.list = options.app.list;
-    this.listenTo(this.list, 'select', this.onItemSelect);
-  },
-
-  show (path) {
-    const that = this;
-    this.fetchList().done(function () {
-      if (path) {
-        const item = that.list.findWhere({ path });
-        if (item != null) {
-          that.showWebService(path);
-        } else {
-          that.showAction(path);
-        }
-      }
-    });
-  },
-
-  showWebService (path) {
-    const item = this.list.findWhere({ path });
-    if (item != null) {
-      item.trigger('select', item);
-    }
-  },
-
-  showAction (path) {
-    const webService = this.list.find(function (item) {
-      return path.indexOf(item.get('path')) === 0;
-    });
-    if (webService != null) {
-      const action = path.substr(webService.get('path').length + 1);
-      webService.trigger('select', webService, { trigger: false, action });
-    }
-  },
-
-  onItemSelect (item, options) {
-    const path = item.get('path');
-    const opts = _.defaults(options || {}, { trigger: true });
-    if (opts.trigger) {
-      this.options.app.router.navigate(path);
-    }
-    this.options.app.listView.highlight(path);
-
-    if (item.get('internal')) {
-      this.options.state.set({ internal: true });
-    }
-
-    const actions = new Backbone.Collection(item.get('actions'));
-    const actionsView = new ActionsView({
-      collection: actions,
-      state: this.options.state
-    });
-    this.options.app.layout.detailsRegion.show(actionsView);
-    this.options.app.layout.headerRegion.show(new HeaderView({ model: item }));
-
-    if (opts.action != null) {
-      const model = actions.findWhere({ key: opts.action });
-      if (model) {
-        if (model.get('internal')) {
-          this.options.state.set({ internal: true });
-        }
-        actionsView.scrollToAction(opts.action);
-      }
-    } else {
-      actionsView.scrollToTop();
-    }
-  },
-
-  fetchList () {
-    return this.list.fetch({ data: { 'include_internals': true } });
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/filters-view.js b/server/sonar-web/src/main/js/apps/api-documentation/filters-view.js
deleted file mode 100644 (file)
index 5e835c3..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import _ from 'underscore';
-import Marionette from 'backbone.marionette';
-import Template from './templates/api-documentation-filters.hbs';
-
-export default Marionette.ItemView.extend({
-  template: Template,
-
-  events: {
-    'change .js-toggle-internal': 'toggleInternal'
-  },
-
-  initialize () {
-    this.listenTo(this.options.state, 'change:internal', this.render);
-  },
-
-  toggleInternal () {
-    this.options.state.set({ internal: !this.options.state.get('internal') });
-  },
-
-  serializeData () {
-    return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
-      state: this.options.state.toJSON()
-    });
-  }
-});
-
-
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/header-view.js b/server/sonar-web/src/main/js/apps/api-documentation/header-view.js
deleted file mode 100644 (file)
index c90eb05..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import Marionette from 'backbone.marionette';
-import Template from './templates/api-documentation-header.hbs';
-
-export default Marionette.ItemView.extend({
-  template: Template,
-
-  modelEvents: {
-    'change': 'render'
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/item-view.js b/server/sonar-web/src/main/js/apps/api-documentation/item-view.js
deleted file mode 100644 (file)
index 2c6e4f1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import _ from 'underscore';
-import Marionette from 'backbone.marionette';
-import Template from './templates/api-documentation-web-service.hbs';
-
-export default Marionette.ItemView.extend({
-  tagName: 'a',
-  className: 'list-group-item',
-  template: Template,
-
-  modelEvents: {
-    'change': 'render'
-  },
-
-  events: {
-    'click': 'onClick'
-  },
-
-  initialize () {
-    this.listenTo(this.options.state, 'change:query', this.toggleHidden);
-    this.listenTo(this.options.state, 'change:internal', this.toggleHidden);
-  },
-
-  shouldBeHidden () {
-    const that = this;
-    const match = this.options.state.match(this.model.get('path')) ||
-        _.some(this.model.get('actions'), function (action) {
-          const test = action.path + '/' + action.key;
-          return that.options.state.match(test, action.internal);
-        });
-
-    const showInternal = this.options.state.get('internal');
-    const hideMe = this.model.get('internal') && !showInternal;
-    return !match || hideMe;
-  },
-
-  onRender () {
-    this.$el.attr('data-path', this.model.get('path'));
-    this.$el.toggleClass('active', this.options.highlighted);
-    this.toggleHidden();
-    this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'right' });
-  },
-
-  onClick (e) {
-    e.preventDefault();
-    this.model.trigger('select', this.model);
-  },
-
-  toggleHidden () {
-    this.$el.toggleClass('hidden', this.shouldBeHidden());
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/layout.js b/server/sonar-web/src/main/js/apps/api-documentation/layout.js
deleted file mode 100644 (file)
index 51d449a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import Marionette from 'backbone.marionette';
-import Template from './templates/api-documentation-layout.hbs';
-
-export default Marionette.LayoutView.extend({
-  template: Template,
-
-  regions: {
-    headerRegion: '.search-navigator-workspace-header',
-    actionsRegion: '.search-navigator-filters',
-    searchRegion: '.api-documentation-search',
-    resultsRegion: '.api-documentation-results',
-    detailsRegion: '.search-navigator-workspace-details'
-  },
-
-  onRender () {
-    const navigator = this.$('.search-navigator');
-    navigator.addClass('sticky search-navigator-extended-view');
-    const top = navigator.offset().top;
-    this.$('.search-navigator-workspace-header').css({ top });
-    this.$('.search-navigator-side').css({ top }).isolatedScroll();
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/list-view.js b/server/sonar-web/src/main/js/apps/api-documentation/list-view.js
deleted file mode 100644 (file)
index c6319e5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import Marionette from 'backbone.marionette';
-import ItemView from './item-view';
-
-export default Marionette.CollectionView.extend({
-  className: 'list-group',
-  childView: ItemView,
-
-  childViewOptions (model) {
-    return {
-      collectionView: this,
-      highlighted: model.get('path') === this.highlighted,
-      state: this.options.state
-    };
-  },
-
-  highlight (path) {
-    this.highlighted = path;
-    this.render();
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/list.js b/server/sonar-web/src/main/js/apps/api-documentation/list.js
deleted file mode 100644 (file)
index 3ecd8fd..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import _ from 'underscore';
-import Backbone from 'backbone';
-
-export default Backbone.Collection.extend({
-  url: '/api/webservices/list',
-  comparator: 'path',
-
-  parse (r) {
-    return r.webServices.map(function (webService) {
-      const internal = _.every(webService.actions, function (action) {
-        return action.internal;
-      });
-      const actions = webService.actions.map(function (action) {
-        return _.extend(action, { path: webService.path });
-      });
-      return _.extend(webService, {
-        internal,
-        actions
-      });
-    });
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/router.js b/server/sonar-web/src/main/js/apps/api-documentation/router.js
deleted file mode 100644 (file)
index 4519399..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import Backbone from 'backbone';
-
-export default Backbone.Router.extend({
-  routes: {
-    '*path': 'show'
-  },
-
-  initialize (options) {
-    this.app = options.app;
-  },
-
-  show (path) {
-    this.app.controller.show(path);
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/search-view.js b/server/sonar-web/src/main/js/apps/api-documentation/search-view.js
deleted file mode 100644 (file)
index b837e3f..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import _ from 'underscore';
-import Marionette from 'backbone.marionette';
-import Template from './templates/api-documentation-search.hbs';
-
-export default Marionette.ItemView.extend({
-  template: Template,
-
-  ui: {
-    input: '.search-box-input'
-  },
-
-  events: {
-    'keyup @ui.input': 'onChange',
-    'search @ui.input': 'onChange'
-  },
-
-  initialize () {
-    this.query = '';
-    this.debouncedFilter = _.debounce(this.filter, 250);
-  },
-
-  onChange () {
-    const query = this.ui.input.val();
-    if (query === this.query) {
-      return;
-    }
-    this.query = this.ui.input.val();
-    this.debouncedFilter(query);
-  },
-
-  filter (query) {
-    this.options.state.set({ query });
-  }
-});
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-action.hbs b/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-action.hbs
deleted file mode 100644 (file)
index bf2e964..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<header class="page-header">
-  <h3 class="page-title big">{{#if post}}POST{{else}}GET{{/if}} {{this.path}}/{{key}}</h3>
-
-  <div class="page-actions">
-    {{#if internal}}
-      <span class="spacer-right">
-        <span class="badge" data-toggle="tooltip" title="{{t 'api_documentation.internal_tooltip'}}">internal</span>
-      </span>
-    {{/if}}
-    {{#if deprecatedSince}}
-      <span class="spacer-right">
-        <span class="badge badge-danger" data-toggle="tooltip"
-              title="{{t 'api_documentation.deprecation_tooltip'}}">Deprecated since {{deprecatedSince}}</span>
-      </span>
-    {{/if}}
-    {{#if since}}
-      <span class="spacer-right">
-        <span class="note">Since {{since}}</span>
-      </span>
-    {{/if}}
-
-    <a class="js-permalink icon-link" href="{{link '/api_documentation/' this.path '/' key}}" target="_blank"></a>
-  </div>
-</header>
-
-<div class="markdown">{{{description}}}</div>
-
-{{#if params}}
-  <h4 class="spacer-top little-spacer-bottom">Parameters</h4>
-  <table class="width-100 data zebra">
-    {{#each params}}
-      <tr>
-        <td style="width: 10em;">
-          <code>{{key}}</code>
-          <div class="note">{{#if required}}required{{else}}optional{{/if}}</div>
-          {{#if since}}
-            <div class="note">since {{since}}</div>
-          {{/if}}
-          {{#if deprecatedSince}}
-            <span class="badge badge-danger little-spacer-top" data-toggle="tooltip"
-                  title="{{t 'api_documentation.deprecation_tooltip'}}">deprecated since {{deprecatedSince}}</span>
-          {{/if}}
-        </td>
-        <td>
-          <div class="markdown">{{{description}}}</div>
-
-          {{#if possibleValues}}
-            <p class="little-spacer-top">
-              <strong>Possible values:</strong>
-            </p>
-            <ul class="list-styled">
-              {{#each possibleValues}}
-                <li class="little-spacer-top"><code>{{this}}</code></li>
-              {{/each}}
-            </ul>
-          {{/if}}
-
-          {{#if defaultValue}}
-            <p class="little-spacer-top">
-              <strong>Default value:</strong> <code>{{defaultValue}}</code>
-            </p>
-          {{/if}}
-
-          {{#if exampleValue}}
-            <p class="little-spacer-top">
-              <strong>Example value:</strong> <code>{{exampleValue}}</code>
-            </p>
-          {{/if}}
-        </td>
-      </tr>
-    {{/each}}
-  </table>
-{{/if}}
-
-{{#if hasResponseExample}}
-  <h4 class="spacer-top">
-    Example Response
-    {{#if responseExample}}
-      <a class="js-hide-response-example little-spacer-left" href="#">Hide</a>
-    {{else}}
-      <a class="js-show-response-example little-spacer-left" href="#">Show</a>
-    {{/if}}
-  </h4>
-
-  {{#if responseExample}}
-    <div class="little-spacer-top">
-      <pre style="white-space: pre-wrap;">{{responseExample}}</pre>
-    </div>
-  {{/if}}
-{{/if}}
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-filters.hbs b/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-filters.hbs
deleted file mode 100644 (file)
index 5941110..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1 class="page-title">Web Service API</h1>
-
-<div class="page-actions">
-  <input class="js-toggle-internal" type="checkbox" id="api-documentation-show-internal" {{#if state.internal}}checked{{/if}}>
-  <label for="api-documentation-show-internal">Show Internal</label>
-</div>
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-header.hbs b/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-header.hbs
deleted file mode 100644 (file)
index f0d5078..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<h2 class="search-navigator-header-component">{{this.path}}</h2>
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-layout.hbs b/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-layout.hbs
deleted file mode 100644 (file)
index f530a84..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<div class="search-navigator sticky">
-  <div class="search-navigator-side search-navigator-side-light">
-    <div class="search-navigator-filters"></div>
-    <div class="api-documentation-search"></div>
-    <div class="api-documentation-results panel"></div>
-  </div>
-
-  <div class="search-navigator-workspace">
-    <div class="search-navigator-workspace-header"></div>
-    <div class="search-navigator-workspace-details"></div>
-  </div>
-</div>
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-search.hbs b/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-search.hbs
deleted file mode 100644 (file)
index 6cad4e3..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<form id="api-documentation-search-form" class="search-box">
-  <span id="api-documentation-search-submit" class="search-box-submit button-clean"><i class="icon-search"></i></span>
-  <input id="api-documentation-search-query" class="search-box-input" type="search" name="q" placeholder="Search" maxlength="100">
-</form>
diff --git a/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-web-service.hbs b/server/sonar-web/src/main/js/apps/api-documentation/templates/api-documentation-web-service.hbs
deleted file mode 100644 (file)
index 5d8fc4b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<h3 class="list-group-item-heading">
-  {{this.path}}
-  {{#if internal}}
-    <span class="badge" data-toggle="tooltip" title="{{t 'api_documentation.internal_tooltip'}}">internal</span>
-  {{/if}}
-</h3>
-<p class="list-group-item-text">{{{description}}}</p>
diff --git a/server/sonar-web/src/main/js/apps/web-api/app.js b/server/sonar-web/src/main/js/apps/web-api/app.js
new file mode 100644 (file)
index 0000000..0ff00d2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { render } from 'react-dom';
+import { Router, Route, Redirect, useRouterHistory } from 'react-router';
+import { createHistory } from 'history';
+
+import WebApiApp from './components/WebApiApp';
+import './styles/web-api.css';
+
+window.sonarqube.appStarted.then(options => {
+  const el = document.querySelector(options.el);
+
+  const history = useRouterHistory(createHistory)({
+    basename: window.sonarqube.urlRoot
+  });
+
+  render((
+      <Router history={history}>
+        <Redirect from="/index" to="/"/>
+        <Route path="/**" component={WebApiApp}/>
+      </Router>
+  ), el);
+});
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Action.js b/server/sonar-web/src/main/js/apps/web-api/components/Action.js
new file mode 100644 (file)
index 0000000..7e9c41c
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link } from 'react-router';
+
+import { getActionKey } from '../utils';
+import Params from './Params';
+import ResponseExample from './ResponseExample';
+import DeprecatedBadge from './DeprecatedBadge';
+import InternalBadge from './InternalBadge';
+
+export default class Action extends React.Component {
+  state = {
+    showParams: false,
+    showResponse: false
+  };
+
+  handleShowParamsClick (e) {
+    e.preventDefault();
+    this.refs.toggleParameters.blur();
+    this.setState({ showParams: !this.state.showParams });
+  }
+
+  handleShowResponseClick (e) {
+    e.preventDefault();
+    this.refs.toggleResponse.blur();
+    this.setState({ showResponse: !this.state.showResponse });
+  }
+
+  render () {
+    const { action, domain } = this.props;
+    const { showParams, showResponse } = this.state;
+    const verb = action.post ? 'POST' : 'GET';
+    const actionKey = getActionKey(domain.path, action.key);
+
+    return (
+        <div id={actionKey} className="web-api-action">
+          <header className="web-api-action-header">
+            <Link
+                to={{ pathname: '/' + actionKey }}
+                className="spacer-right icon-link"/>
+
+            <h3 className="web-api-action-title">
+              {verb}&nbsp;{actionKey}
+            </h3>
+
+            {action.internal && (
+                <span className="spacer-left">
+                  <InternalBadge/>
+                </span>
+            )}
+
+            {action.since && (
+                <span className="spacer-left badge">since {action.since}</span>
+            )}
+
+            {action.deprecatedSince && (
+                <span className="spacer-left">
+                  <DeprecatedBadge since={action.deprecatedSince}/>
+                </span>
+            )}
+          </header>
+
+          <div
+              className="web-api-action-description markdown"
+              dangerouslySetInnerHTML={{ __html: action.description }}/>
+
+          {(action.params || action.hasResponseExample) && (
+              <ul className="web-api-action-actions list-inline">
+                {action.params && (
+                    <li>
+                      <a
+                          ref="toggleParameters"
+                          onClick={this.handleShowParamsClick.bind(this)}
+                          href="#">
+                        {showParams ? 'Hide Parameters' : 'Show Parameters'}
+                      </a>
+                    </li>
+                )}
+
+                {action.hasResponseExample && (
+                    <li>
+                      <a
+                          ref="toggleResponse"
+                          onClick={this.handleShowResponseClick.bind(this)}
+                          href="#">
+                        {showResponse ? 'Hide Response Example' : 'Show Response Example'}
+                      </a>
+                    </li>
+                )}
+              </ul>
+          )}
+
+          {showParams && action.params && <Params params={action.params}/>}
+
+          {showResponse && action.hasResponseExample && <ResponseExample domain={domain} action={action}/>}
+        </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/DeprecatedBadge.js b/server/sonar-web/src/main/js/apps/web-api/components/DeprecatedBadge.js
new file mode 100644 (file)
index 0000000..212e662
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+import { translate } from '../../../helpers/l10n';
+
+export default function DeprecatedBadge ({ since }) {
+  const label = since ? `deprecated since ${since}` : 'deprecated';
+
+  return (
+      <span
+          className="badge badge-warning"
+          title={translate('api_documentation.deprecation_tooltip')}>
+        {label}
+      </span>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Domain.js b/server/sonar-web/src/main/js/apps/web-api/components/Domain.js
new file mode 100644 (file)
index 0000000..df212f6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+import Action from './Action';
+import InternalBadge from './InternalBadge';
+import { getActionKey } from '../utils';
+
+export default function Domain ({ domain, showInternal, showOnlyDeprecated, searchQuery }) {
+  const filteredActions = domain.actions
+      .filter(action => {
+        return showInternal || !action.internal;
+      })
+      .filter(action => {
+        return !showOnlyDeprecated || (showOnlyDeprecated && action.deprecatedSince);
+      })
+      .filter(action => {
+        const actionKey = getActionKey(domain.path, action.key);
+        return actionKey.indexOf(searchQuery) !== -1;
+      });
+
+  return (
+      <div className="web-api-domain">
+        <header className="web-api-domain-header">
+          <h2 className="web-api-domain-title">{domain.path}</h2>
+
+          {domain.internal && (
+              <span className="spacer-left">
+                <InternalBadge/>
+              </span>
+          )}
+        </header>
+
+        {domain.description && (
+            <p className="web-api-domain-description">{domain.description}</p>
+        )}
+
+        <div className="web-api-domain-actions">
+          {filteredActions.map(action => (
+              <Action
+                  key={getActionKey(domain.path, action.key)}
+                  action={action}
+                  domain={domain}
+                  location={location}/>
+          ))}
+        </div>
+      </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/InternalBadge.js b/server/sonar-web/src/main/js/apps/web-api/components/InternalBadge.js
new file mode 100644 (file)
index 0000000..cfb87e6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+import { translate } from '../../../helpers/l10n';
+
+export default function InternalBadge () {
+  return (
+      <span
+          className="badge badge-danger"
+          title={translate('api_documentation.internal_tooltip')}>
+        internal
+      </span>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js
new file mode 100644 (file)
index 0000000..e5d58f5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link } from 'react-router';
+import classNames from 'classnames';
+
+import InternalBadge from './InternalBadge';
+import { getActionKey } from '../utils';
+
+export default function Menu ({ domains, showInternal, showOnlyDeprecated, searchQuery, splat }) {
+  const filteredDomains = (domains || [])
+      .map(domain => {
+        const filteredActions = domain.actions
+            .filter(action => {
+              return showInternal || !action.internal;
+            })
+            .filter(action => {
+              return !showOnlyDeprecated || (showOnlyDeprecated && action.deprecatedSince);
+            })
+            .filter(action => {
+              const actionKey = getActionKey(domain.path, action.key);
+              return actionKey.indexOf(searchQuery) !== -1;
+            });
+        return { ...domain, filteredActions };
+      })
+      .filter(domain => domain.filteredActions.length);
+
+
+  return (
+      <div className="api-documentation-results panel">
+        <div className="list-group">
+          {filteredDomains.map(domain => (
+              <Link
+                  key={domain.path}
+                  className={classNames('list-group-item', { 'active': splat.indexOf(domain.path) === 0 })}
+                  to={domain.path}>
+                <h3 className="list-group-item-heading">
+                  {domain.path}
+                  {domain.internal && (
+                      <InternalBadge/>
+                  )}
+                </h3>
+                <p className="list-group-item-text">
+                  {domain.description}
+                </p>
+              </Link>
+          ))}
+        </div>
+      </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Params.js b/server/sonar-web/src/main/js/apps/web-api/components/Params.js
new file mode 100644 (file)
index 0000000..66018f8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+export default function Params ({ params }) {
+  return (
+      <div className="web-api-params">
+        <table>
+          <tbody>
+          {params.map(param => (
+              <tr key={param.key}>
+                <td style={{ width: 150 }}>
+                  <code>{param.key}</code>
+
+                  <div className="note little-spacer-top">
+                    {param.required ? 'required' : 'optional'}
+                  </div>
+
+                  {param.since && (
+                      <div className="note little-spacer-top">
+                        since {param.since}
+                      </div>
+                  )}
+
+                  {param.deprecatedSince && (
+                      <div className="little-spacer-top">
+                        <span className="badge badge-danger">
+                          deprecated since {param.deprecatedSince}
+                        </span>
+                      </div>
+                  )}
+                </td>
+
+                <td>
+                  <div
+                      className="markdown"
+                      dangerouslySetInnerHTML={{ __html: param.description }}/>
+                </td>
+
+                <td style={{ width: 250 }}>
+                  {param.possibleValues && (
+                      <div>
+                        <h4>Possible values</h4>
+                        <ul className="list-styled">
+                          {param.possibleValues.map(value => (
+                              <li key={value} className="little-spacer-top">
+                                <code>{value}</code>
+                              </li>
+                          ))}
+                        </ul>
+                      </div>
+                  )}
+
+                  {param.defaultValue && (
+                      <div className="little-spacer-top">
+                        <h4>Default value</h4>
+                        <code>{param.defaultValue}</code>
+                      </div>
+                  )}
+
+                  {param.exampleValue && (
+                      <div className="little-spacer-top">
+                        <h4>Example value</h4>
+                        <code>{param.exampleValue}</code>
+                      </div>
+                  )}
+                </td>
+              </tr>
+          ))}
+          </tbody>
+        </table>
+      </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/ResponseExample.js b/server/sonar-web/src/main/js/apps/web-api/components/ResponseExample.js
new file mode 100644 (file)
index 0000000..70e1791
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+
+import { fetchResponseExample as fetchResponseExampleApi } from '../../../api/web-api';
+
+export default class ResponseExample extends React.Component {
+  state = {};
+
+  componentDidMount () {
+    this.mounted = true;
+    this.fetchResponseExample();
+  }
+
+  componentDidUpdate (nextProps) {
+    if (nextProps.action !== this.props.action) {
+      this.fetchResponseExample();
+    }
+  }
+
+  componentWillUnmount () {
+    this.mounted = false;
+  }
+
+  fetchResponseExample () {
+    const { domain, action } = this.props;
+    fetchResponseExampleApi(domain.path, action.key)
+        .then(responseExample => this.setState({ responseExample }));
+  }
+
+  render () {
+    const { responseExample } = this.state;
+
+    return (
+        <div className="web-api-response">
+          {responseExample && (
+              <pre style={{ whiteSpace: 'pre-wrap' }}>{responseExample.example}</pre>
+          )}
+        </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Search.js b/server/sonar-web/src/main/js/apps/web-api/components/Search.js
new file mode 100644 (file)
index 0000000..9ff6027
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import _ from 'underscore';
+import React from 'react';
+
+import DeprecatedBadge from './DeprecatedBadge';
+import InternalBadge from './InternalBadge';
+import Checkbox from '../../../components/shared/checkbox';
+
+export default class Search extends React.Component {
+  constructor (props) {
+    super(props);
+    this.state = { query: '' };
+    this.actuallySearch = _.debounce(this.actuallySearch.bind(this), 250);
+  }
+
+  handleSearch (e) {
+    const { value } = e.target;
+    this.setState({ query: value });
+    this.actuallySearch();
+  }
+
+  actuallySearch () {
+    const { onSearch } = this.props;
+    onSearch(this.state.query);
+  }
+
+  render () {
+    const { showInternal, showOnlyDeprecated, onToggleInternal, onToggleDeprecated } = this.props;
+
+    return (
+        <div className="web-api-search">
+          <div>
+            <i className="icon-search"/>
+            <input
+                className="spacer-left input-large"
+                type="search"
+                value={this.state.query}
+                placeholder="Search..."
+                onChange={this.handleSearch.bind(this)}/>
+          </div>
+
+          <div className="big-spacer-top">
+            <Checkbox
+                initiallyChecked={showInternal}
+                onCheck={onToggleInternal}/>
+            {' '}
+            <span
+                style={{ cursor: 'pointer' }}
+                onClick={onToggleInternal}>
+              <InternalBadge/>
+            </span>
+          </div>
+
+          <div className="spacer-top">
+            <Checkbox
+                initiallyChecked={showOnlyDeprecated}
+                onCheck={onToggleDeprecated}/>
+            {' '}
+            <span
+                style={{ cursor: 'pointer' }}
+                onClick={onToggleDeprecated}>
+              Only <DeprecatedBadge/>
+            </span>
+          </div>
+        </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js
new file mode 100644 (file)
index 0000000..332d18f
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { Link } from 'react-router';
+
+import { fetchWebApi } from '../../../api/web-api';
+import Menu from './Menu';
+import Search from './Search';
+import Domain from './Domain';
+import { getActionKey } from '../utils';
+
+export default class WebApiApp extends React.Component {
+  state = {
+    domains: [],
+    searchQuery: '',
+    showInternal: false,
+    showOnlyDeprecated: false
+  };
+
+  componentDidMount () {
+    this.mounted = true;
+    this.scrollToAction = this.scrollToAction.bind(this);
+    this.fetchList();
+    document.getElementById('footer').classList.add('search-navigator-footer');
+  }
+
+  componentDidUpdate () {
+    this.toggleInternalInitially();
+    this.scrollToAction();
+  }
+
+  componentWillUnmount () {
+    this.mounted = false;
+    document.getElementById('footer').classList.delete('search-navigator-footer');
+  }
+
+  fetchList (cb) {
+    fetchWebApi().then(domains => {
+      if (this.mounted) {
+        this.setState({ domains }, cb);
+      }
+    });
+  }
+
+  scrollToAction () {
+    const { splat } = this.props.params;
+    this.scrollToElement(splat);
+  }
+
+  scrollToElement (id) {
+    const element = document.getElementById(id);
+
+    if (element) {
+      const rect = element.getBoundingClientRect();
+      const top = rect.top + window.pageYOffset - 20;
+
+      window.scrollTo(0, top);
+    } else {
+      window.scrollTo(0, 0);
+    }
+  }
+
+  toggleInternalInitially () {
+    const { splat } = this.props.params;
+    const { domains, showInternal } = this.state;
+
+    if (!showInternal) {
+      domains.forEach(domain => {
+        if (domain.path === splat && domain.internal) {
+          this.setState({ showInternal: true });
+        }
+        domain.actions.forEach(action => {
+          const actionKey = getActionKey(domain.path, action.key);
+          if (actionKey === splat && action.internal) {
+            this.setState({ showInternal: true });
+          }
+        });
+      });
+    }
+  }
+
+  handleSearch (searchQuery) {
+    this.setState({ searchQuery });
+  }
+
+  handleToggleInternal () {
+    const { splat } = this.props.params;
+    const { router } = this.context;
+    const { domains } = this.state;
+    const domain = domains.find(domain => splat.indexOf(domain.path) === 0);
+    const showInternal = !this.state.showInternal;
+
+    if (domain && domain.internal && !showInternal) {
+      router.push('/');
+    }
+
+    this.setState({ showInternal });
+  }
+
+  handleToggleDeprecated () {
+    this.setState({ showOnlyDeprecated: !this.state.showOnlyDeprecated });
+  }
+
+  render () {
+    const { splat } = this.props.params;
+    const { domains, showInternal, showOnlyDeprecated, searchQuery } = this.state;
+
+    const domain = domains.find(domain => splat.indexOf(domain.path) === 0);
+
+    return (
+        <div className="search-navigator sticky">
+          <div className="search-navigator-side search-navigator-side-light" style={{ top: 30 }}>
+            <div className="web-api-page-header">
+              <Link to="/">
+                <h1>Web API</h1>
+              </Link>
+            </div>
+
+            <Search
+                showInternal={showInternal}
+                showOnlyDeprecated={showOnlyDeprecated}
+                onSearch={this.handleSearch.bind(this)}
+                onToggleInternal={this.handleToggleInternal.bind(this)}
+                onToggleDeprecated={this.handleToggleDeprecated.bind(this)}/>
+
+            <Menu
+                domains={this.state.domains}
+                showInternal={showInternal}
+                showOnlyDeprecated={showOnlyDeprecated}
+                searchQuery={searchQuery}
+                splat={splat}/>
+          </div>
+
+          <div className="search-navigator-workspace">
+            {domain && (
+                <Domain
+                    key={domain.path}
+                    domain={domain}
+                    showInternal={showInternal}
+                    showOnlyDeprecated={showOnlyDeprecated}
+                    searchQuery={searchQuery}/>
+            )}
+          </div>
+        </div>
+    );
+  }
+}
+
+WebApiApp.contextTypes = {
+  router: React.PropTypes.object.isRequired
+};
diff --git a/server/sonar-web/src/main/js/apps/web-api/styles/web-api.css b/server/sonar-web/src/main/js/apps/web-api/styles/web-api.css
new file mode 100644 (file)
index 0000000..e5b5729
--- /dev/null
@@ -0,0 +1,72 @@
+.web-api-page-header {
+  margin: 10px 20px;
+}
+
+.web-api-search {
+  margin: 20px 10px 0;
+  padding: 0 10px 20px;
+  border-bottom: 1px solid #e6e6e6;
+}
+
+.web-api-search .icon-search {
+  color: #cdcdcd;
+}
+
+.web-api-domain {
+  padding: 10px 20px;
+}
+
+.web-api-domain-header,
+.web-api-action-header {
+  display: flex;
+  align-items: center;
+}
+
+.web-api-domain-title {
+  font-size: 18px;
+  font-weight: 400;
+}
+
+.web-api-domain-description {
+  margin-top: 10px;
+  line-height: 1.5;
+}
+
+.web-api-domain-actions {
+}
+
+.web-api-action {
+  padding-top: 30px;
+}
+
+.web-api-action-title {
+  font-weight: 500;
+}
+
+.web-api-action-description {
+  margin-top: 10px;
+}
+
+.web-api-action-actions {
+  margin-top: 10px;
+}
+
+.web-api-params,
+.web-api-response {
+  margin-top: 10px;
+}
+
+.web-api-params > table {
+  width: 100%;
+  table-layout: fixed;
+}
+
+.web-api-params td {
+  vertical-align: top;
+  padding: 8px 10px;
+  border-top: 1px solid #e6e6e6;
+}
+
+.web-api-params tr:first-child td {
+  border-top: none;
+}
diff --git a/server/sonar-web/src/main/js/apps/web-api/utils.js b/server/sonar-web/src/main/js/apps/web-api/utils.js
new file mode 100644 (file)
index 0000000..6e6de08
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+export function getActionKey (domain, action) {
+  return domain + '/' + action;
+}
index aa1800a138a2ade475db78eee35e28519a01db3e..9329fcb6e76eee899a9214d4b8b8720c9c1a6942 100644 (file)
@@ -8,7 +8,7 @@
     <a href="http://www.sonarqube.org/documentation" target="sonar_doc">Documentation</a> -
     <a href="http://www.sonarqube.org/support" target="support">Get Support</a> -
     <a href="http://redirect.sonarsource.com/doc/plugin-library.html" target="plugins">Plugins</a> -
-    <a href="{{link '/api_documentation'}}">Web Service API</a>
+    <a href="{{link '/web_api'}}">Web API</a>
   </div>
 
   <h2 class="spacer-top spacer-bottom">{{t 'shortcuts.modal_title'}}</h2>
diff --git a/server/sonar-web/src/main/less/pages/api-documentation.less b/server/sonar-web/src/main/less/pages/api-documentation.less
deleted file mode 100644 (file)
index 48076fa..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-@import (reference) "../mixins";
-@import (reference) "../variables";
-
-
-.api-documentation-search {
-  padding: 10px;
-
-  .search-box-input {
-    background-color: @barBackgroundColor;
-  }
-}
index b1b5e033e2947ac778cf9c4a6eed1001dffbeac0..abba2b8e055472e34eb4bf4bf7a60553bcb26dc8 100644 (file)
@@ -64,7 +64,6 @@
 @import "pages/quality-gates";
 @import "pages/maintenance";
 @import "pages/login";
-@import "pages/api-documentation";
 @import "pages/overview";
 
 @import 'style';
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api_documentation_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api_documentation_controller.rb
deleted file mode 100644 (file)
index 2505027..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# SonarQube, open source software quality management tool.
-# Copyright (C) 2008-2014 SonarSource
-# mailto:contact AT sonarsource DOT com
-#
-# SonarQube is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# SonarQube is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#
-
-class ApiDocumentationController < ApplicationController
-
-  # GET /api_documentation/index
-  def index
-
-  end
-
-end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/web_api_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/web_api_controller.rb
new file mode 100644 (file)
index 0000000..d9fe271
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+class WebApiController < ApplicationController
+
+  def index
+
+  end
+
+end
index 94e2eb4f7ebe25f581d58d985037bd1e5950ee03..55cfc7eb40914ffd5760a2ba1d5b3fc911ccc294 100644 (file)
@@ -56,7 +56,7 @@
       <a href="http://www.sonarqube.org/documentation" target="sonar_doc">Documentation</a> -
       <a href="http://www.sonarqube.org/support" target="support">Get Support</a> -
       <a href="http://redirect.sonarsource.com/doc/plugin-library.html" target="plugins">Plugins</a> -
-      <a href="/api_documentation">Web Service API</a>
+      <a href="/web_api">Web API</a>
     </div>
     <!--[if lte IE 8 ]><p class="spacer-top alert alert-danger">IE 8 is not supported. Some widgets may not be properly displayed. Please switch to a <a target="_blank" href="http://redirect.sonarsource.com/doc/requirements.html">supported version or another supported browser</a>.</p><!--<![endif]-->
   </div>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/web_api/index.html.erb
new file mode 100644 (file)
index 0000000..5e27644
--- /dev/null
@@ -0,0 +1,6 @@
+<% content_for :extra_script do %>
+  <script>
+    window.sonarqube.urlRoot = '/web_api';
+  </script>
+  <script src="/js/bundles/web-api.js?v=<%= sonar_version -%>"></script>
+<% end %>
index 69814d108fb7d518d2aa7ab964ae56fd00ffa55d..efa07fcac91e7d58e9b521e22953cbea59c29988 100644 (file)
@@ -31,7 +31,7 @@ ActionController::Routing::Routes.draw do |map|
   map.connect 'charts/:action/:project_id/:metric_id', :controller => 'charts'
   map.connect 'rules_configuration/:action/:language/:name/:plugin.:format', :controller => 'rules_configuration'
 
-  map.connect 'api_documentation/*other', :controller => 'api_documentation', :action => 'index'
+  map.connect 'web_api/*other', :controller => 'web_api', :action => 'index'
   map.connect 'quality_gates/*other', :controller => 'quality_gates', :action => 'index'
   map.connect 'overview/*other', :controller => 'overview', :action => 'index'
   map.connect 'account/update_notifications', :controller => 'account', :action => 'update_notifications'
index eb1df2916a9b41417a073fcb55c46fa439756bde..f74429fd220edc3a066126e2fca14f26bd8288bf 100644 (file)
@@ -51,6 +51,7 @@ module.exports = {
     'system': './src/main/js/apps/system/app.js',
     'update-center': './src/main/js/apps/update-center/app.js',
     'users': './src/main/js/apps/users/app.js',
+    'web-api': './src/main/js/apps/web-api/app.js',
 
     'widgets': './src/main/js/widgets/widgets.js'
   },