diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2015-05-18 16:29:19 +0200 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-05-19 18:20:09 +0200 |
commit | e59e4aa2c06a57566f148f4217d286461231ae58 (patch) | |
tree | ad0918eb06b2474a6c71997b7ff573bbb93e0170 /server/sonar-web/src/main/coffee/apps | |
parent | 8d82c9cf9ba88c1517604b4063ad0fc2a9a1bb9a (diff) | |
download | sonarqube-e59e4aa2c06a57566f148f4217d286461231ae58.tar.gz sonarqube-e59e4aa2c06a57566f148f4217d286461231ae58.zip |
change web structure: separate components
Diffstat (limited to 'server/sonar-web/src/main/coffee/apps')
103 files changed, 5174 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/app.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/app.coffee new file mode 100644 index 00000000000..0d7c20d4bd4 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/app.coffee @@ -0,0 +1,88 @@ +# +# 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. +# +define [ + './router' + './layout' + './models/reports' + './views/reports-view' + './views/actions-view' +], ( + Router + Layout + Reports + ReportsView + ActionsView +) -> + + # Add html class to mark the page as navigator page + jQuery('html').addClass 'navigator-page' + + + # Create an Application + App = new Marionette.Application + + + App.fetchReports = -> + fetch = if @state.get 'active' then @reports.fetchActive() else @reports.fetchHistory() + @layout.showSpinner 'actionsRegion' + @layout.resultsRegion.reset() + fetch.done => + @state.set page: @reports.paging.page + @reportsView = new ReportsView + app: @ + collection: @reports + @layout.resultsRegion.show @reportsView + + unless @state.get('active') || @reports.paging.maxResultsReached + @reportsView.bindScrollEvents() unless @state.get 'active' + + @actionsView = new ActionsView + app: @ + collection: @reports + @layout.actionsRegion.show @actionsView + + + App.fetchNextPage = -> + @reports.fetchHistory + data: + p: @state.get('page') + 1 + remove: false + .done => + @state.set page: @reports.paging.page + + + App.addInitializer -> + @state = new Backbone.Model() + @state.on 'change:active', => @fetchReports() + + + App.addInitializer -> + @layout = new Layout app: @ + jQuery('#analysis-reports').empty().append @layout.render().el + + + App.addInitializer -> + @reports = new Reports() + @router = new Router app: @ + Backbone.history.start() + + + l10nXHR = window.requestMessages() + jQuery.when(l10nXHR).done -> App.start() diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/layout.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/layout.coffee new file mode 100644 index 00000000000..5aa028e86b2 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/layout.coffee @@ -0,0 +1,37 @@ +# +# 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. +# + +define [ + './templates' +], -> + + class extends Marionette.Layout + template: Templates['analysis-reports-layout'] + + + + regions: + actionsRegion: '.analysis-reports-actions' + resultsRegion: '.analysis-reports-results' + + + showSpinner: (region) -> + @[region].show new Marionette.ItemView + template: _.template('<i class="spinner"></i>') diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/models/report.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/models/report.coffee new file mode 100644 index 00000000000..28700ed4a62 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/models/report.coffee @@ -0,0 +1,24 @@ +# +# 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. +# + +define -> + + + class extends Backbone.Model diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/models/reports.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/models/reports.coffee new file mode 100644 index 00000000000..1689eed3e65 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/models/reports.coffee @@ -0,0 +1,50 @@ +# +# 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. +# + +define [ + './report' +], ( + Report +) -> + + + class extends Backbone.Collection + model: Report + + + parse: (r) -> + @paging = + page: r.p + pageSize: r.ps + total: r.total + maxResultsReached: r.p * r.ps >= r.total + r.reports + + + fetchActive: -> + @fetch { url: "#{baseUrl}/api/computation/queue" }, { reset: true } + + + fetchHistory: (options = { }) -> + _.extend options, + url: "#{baseUrl}/api/computation/history" + options.data = options.data || {} + options.data.ps = 50 + @fetch options, { reset: true } diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/router.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/router.coffee new file mode 100644 index 00000000000..1bebf0ee964 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/router.coffee @@ -0,0 +1,42 @@ +# +# 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. +# + +define -> + + class AppRouter extends Backbone.Router + + routes: + '': 'showCurrent' + 'current': 'showCurrent' + 'past': 'showPast' + + + initialize: (options) -> + @options = options + + + showCurrent: -> + @navigate 'current' + @options.app.state.set active: true + + + showPast: -> + @navigate 'past' + @options.app.state.set active: false diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-actions.hbs b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-actions.hbs new file mode 100644 index 00000000000..90f24e63851 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-actions.hbs @@ -0,0 +1,6 @@ +<ul class="tabs"> + <li><a class="js-show-current-activity {{#if state.active}}selected{{/if}}">{{t 'analysis_reports.current_activity'}}</a></li> + <li><a class="js-show-past-reports {{#unless state.active}}selected{{/unless}}">{{t 'analysis_reports.past_reports'}}</a></li> +</ul> + +<div class="analysis-reports-total">{{tp 'analysis_reports.x_reports' total}}</div> diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-empty.hbs b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-empty.hbs new file mode 100644 index 00000000000..b044d70fc04 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-empty.hbs @@ -0,0 +1 @@ +No reports to show diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-layout.hbs b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-layout.hbs new file mode 100644 index 00000000000..e00c677a6d6 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-layout.hbs @@ -0,0 +1,10 @@ +<header class="page-header"> + <h1 class="page-title">{{t 'analysis_reports.page'}}</h1> + <p class="page-description"> + The server is in charge to process reports submitted by batch analyses. This page allows to monitor the queue of + pending reports to process, and gives access to the history of past analyses. + </p> +</header> + +<div class="analysis-reports-actions"></div> +<div class="analysis-reports-results"></div> diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-report.hbs b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-report.hbs new file mode 100644 index 00000000000..b816c2fbec7 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/templates/analysis-reports-report.hbs @@ -0,0 +1,24 @@ +<div class="line"> + <span class="analysis-reports-project"> + <i class="icon-qualifier-trk"></i> + <a href="{{dashboardUrl projectKey}}">{{projectName}}</a> + </span> + + <span class="analysis-reports-timestamp line-small"> + {{#if submittedAt}}Submitted: {{dt submittedAt}}<br>{{/if}} + {{#if startedAt}}Started: {{dt startedAt}}<br>{{/if}} + {{#if finishedAt}}Finished: {{dt finishedAt}}<br>{{/if}} + </span> + + {{#if duration}} + <span class="analysis-reports-timestamp line-small"> + Duration: + {{#gt duration.hours 0}}{{duration.hours}}h{{/gt}} + {{#gt duration.minutes 0}}{{duration.minutes}}m{{/gt}} + {{duration.seconds}}s + </span> + {{/if}} + +</div> + +<div class="analysis-reports-report-id">{{key}} {{status}}</div> diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/views/actions-view.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/actions-view.coffee new file mode 100644 index 00000000000..89ae9048c52 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/actions-view.coffee @@ -0,0 +1,50 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class extends Marionette.ItemView + template: Templates['analysis-reports-actions'] + + + events: + 'click .js-show-past-reports': 'showPastReports' + 'click .js-show-current-activity': 'showCurrentActivity' + + + initialize: (options) -> + @listenTo options.collection, 'all', @render + @listenTo options.app.state, 'change', @render + + + showPastReports: -> + @options.app.router.navigate 'past', trigger: true + + + showCurrentActivity: -> + @options.app.router.navigate 'current', trigger: true + + + serializeData: -> + _.extend super, + state: @options.app.state.toJSON() + total: @collection.paging.total || @collection.length diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/views/report-view.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/report-view.coffee new file mode 100644 index 00000000000..4af3d06f602 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/report-view.coffee @@ -0,0 +1,50 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class extends Marionette.ItemView + tagName: 'li' + template: Templates['analysis-reports-report'] + + + onRender: -> + status = @model.get 'status' + @$el.addClass 'analysis-reports-report-pending' if status is 'PENDING' + @$el.addClass 'analysis-reports-report-working' if status is 'WORKING' + @$el.addClass 'analysis-reports-report-done' if status is 'SUCCESS' + @$el.addClass 'analysis-reports-report-cancelled' if status is 'CANCELLED' + @$el.addClass 'analysis-reports-report-failed' if status is 'FAIL' + + + serializeData: -> + duration = null + if @model.has 'startedAt' + startedAtMoment = moment @model.get 'startedAt' + finishedAtMoment = moment(@model.get('finishedAt') || new Date()) + duration = finishedAtMoment.diff startedAtMoment + duration = + seconds: Math.floor (duration / 1000) % 60 + minutes: Math.floor (duration / (1000 * 60)) % 60 + hours: Math.floor (duration / (1000 * 60 * 60)) % 24 + _.extend super, + duration: duration diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/views/reports-empty-view.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/reports-empty-view.coffee new file mode 100644 index 00000000000..c5c16ea59c0 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/reports-empty-view.coffee @@ -0,0 +1,28 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class extends Marionette.ItemView + className: 'analysis-reports-no-results' + tagName: 'li' + template: Templates['analysis-reports-empty'] diff --git a/server/sonar-web/src/main/coffee/apps/analysis-reports/views/reports-view.coffee b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/reports-view.coffee new file mode 100644 index 00000000000..32efc6f0707 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/analysis-reports/views/reports-view.coffee @@ -0,0 +1,64 @@ +# +# 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. +# + +define [ + './report-view' + './reports-empty-view' +], ( + ReportView + EmptyView +) -> + + $ = jQuery + + + class extends Marionette.CollectionView + tagName: 'ol' + className: 'navigator-results-list' + itemView: ReportView + emptyView: EmptyView + + + itemViewOptions: -> + listView: @, app: @options.app + + + initialize: -> + @loadMoreThrottled = _.throttle @loadMore, 200 + + + onClose: -> + @unbindScrollEvents() + + + bindScrollEvents: -> + $(window).on 'scroll', (=> @loadMoreThrottled()) + + + unbindScrollEvents: -> + $(window).off 'scroll' + + + loadMore: -> + lastItem = this.children.findByIndex(@collection.length - 1) + if $(window).scrollTop() + $(window).outerHeight() >= lastItem.$el.offset().top - 40 + @unbindScrollEvents() + @options.app.fetchNextPage().done => + @bindScrollEvents() unless @collection.paging.maxResultsReached diff --git a/server/sonar-web/src/main/coffee/apps/issues/app-context.coffee b/server/sonar-web/src/main/coffee/apps/issues/app-context.coffee new file mode 100644 index 00000000000..556b93e1e00 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/app-context.coffee @@ -0,0 +1,131 @@ +# +# 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. +# +define [ + './models/state' + './layout' + './models/issues' + 'components/navigator/models/facets' + './models/filters' + + './controller' + './router' + + './workspace-list-view' + './workspace-header-view' + + './facets-view' + './filters-view' +], ( + State + Layout + Issues + Facets + Filters + + Controller + Router + + WorkspaceListView + WorkspaceHeaderView + + FacetsView + FiltersView +) -> + + $ = jQuery + App = new Marionette.Application + + + App.getContextQuery = -> + componentUuids: window.config.resource + + + App.getRestrictedFacets = -> + 'TRK': ['projectUuids'] + 'BRC': ['projectUuids'] + 'DIR': ['projectUuids', 'moduleUuids', 'directories'] + 'DEV': ['authors'] + 'DEV_PRJ': ['projectUuids', 'authors'] + + + App.updateContextFacets = -> + facets = @state.get 'facets' + allFacets = @state.get 'allFacets' + facetsFromServer = @state.get 'facetsFromServer' + @state.set + facets: facets + allFacets: _.difference allFacets, @getRestrictedFacets()[window.config.resourceQualifier] + facetsFromServer: _.difference facetsFromServer, @getRestrictedFacets()[window.config.resourceQualifier] + + + App.addInitializer -> + @state = new State + isContext: true, + contextQuery: @getContextQuery() + contextComponentUuid: window.config.resource + contextComponentName: window.config.resourceName + contextComponentQualifier: window.config.resourceQualifier + @updateContextFacets() + @list = new Issues() + @facets = new Facets() + @filters = new Filters() + + + App.addInitializer -> + @layout = new Layout app: @ + $('.issues').empty().append @layout.render().el + $('#footer').addClass('search-navigator-footer'); + + + App.addInitializer -> + @controller = new Controller app: @ + + + App.addInitializer -> + @issuesView = new WorkspaceListView + app: @ + collection: @list + @layout.workspaceListRegion.show @issuesView + @issuesView.bindScrollEvents() + + + App.addInitializer -> + @workspaceHeaderView = new WorkspaceHeaderView + app: @ + collection: @list + @layout.workspaceHeaderRegion.show @workspaceHeaderView + + + App.addInitializer -> + @facetsView = new FacetsView + app: @ + collection: @facets + @layout.facetsRegion.show @facetsView + + + App.addInitializer -> + @controller.fetchFilters().done => + key.setScope 'list' + @router = new Router app: @ + Backbone.history.start() + + + l10nXHR = window.requestMessages() + jQuery.when(l10nXHR).done -> App.start() diff --git a/server/sonar-web/src/main/coffee/apps/issues/app-new.coffee b/server/sonar-web/src/main/coffee/apps/issues/app-new.coffee new file mode 100644 index 00000000000..c69a48e6207 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/app-new.coffee @@ -0,0 +1,109 @@ +# +# 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. +# +define [ + './models/state' + './layout' + './models/issues' + 'components/navigator/models/facets' + './models/filters' + + './controller' + './router' + + './workspace-list-view' + './workspace-header-view' + + './facets-view' + './filters-view' +], ( + State + Layout + Issues + Facets + Filters + + Controller + Router + + WorkspaceListView + WorkspaceHeaderView + + FacetsView + FiltersView +) -> + + $ = jQuery + App = new Marionette.Application + + App.addInitializer -> + @state = new State() + @list = new Issues() + @facets = new Facets() + @filters = new Filters() + + + App.addInitializer -> + @layout = new Layout app: @ + $('.issues').empty().append @layout.render().el + $('#footer').addClass('search-navigator-footer'); + + + App.addInitializer -> + @controller = new Controller app: @ + + + App.addInitializer -> + @issuesView = new WorkspaceListView + app: @ + collection: @list + @layout.workspaceListRegion.show @issuesView + @issuesView.bindScrollEvents() + + + App.addInitializer -> + @workspaceHeaderView = new WorkspaceHeaderView + app: @ + collection: @list + @layout.workspaceHeaderRegion.show @workspaceHeaderView + + + App.addInitializer -> + @facetsView = new FacetsView + app: @ + collection: @facets + @layout.facetsRegion.show @facetsView + + + App.addInitializer -> + @filtersView = new FiltersView + app: @ + collection: @filters + @layout.filtersRegion.show @filtersView + + + App.addInitializer -> + @controller.fetchFilters().done => + key.setScope 'list' + @router = new Router app: @ + Backbone.history.start() + + + l10nXHR = window.requestMessages() + jQuery.when(l10nXHR).done -> App.start() diff --git a/server/sonar-web/src/main/coffee/apps/issues/component-viewer/issue-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/component-viewer/issue-view.coffee new file mode 100644 index 00000000000..b626cff1070 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/component-viewer/issue-view.coffee @@ -0,0 +1,36 @@ +# +# 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. +# + +define [ + '../workspace-list-item-view' +], ( + IssueView +) -> + + class extends IssueView + + onRender: -> + super + @$el.removeClass 'issue-navigate-right' + + + serializeData: -> + _.extend super, + showComponent: false diff --git a/server/sonar-web/src/main/coffee/apps/issues/component-viewer/main.coffee b/server/sonar-web/src/main/coffee/apps/issues/component-viewer/main.coffee new file mode 100644 index 00000000000..1a23d070331 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/component-viewer/main.coffee @@ -0,0 +1,192 @@ +# +# 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. +# + +define [ + 'components/source-viewer/main' + '../models/issues' + './issue-view' + '../templates' +], ( + SourceViewer + Issues + IssueView +) -> + + $ = jQuery + + TOP_OFFSET = 38 + BOTTOM_OFFSET = 10 + + + class extends SourceViewer + + events: -> + _.extend super, + 'click .js-close-component-viewer': 'closeComponentViewer' + 'click .code-issue': 'selectIssue' + + + initialize: (options) -> + super + @listenTo options.app.state, 'change:selectedIndex', @select + + + onLoaded: -> + super + @bindShortcuts() + if @baseIssue? + @scrollToLine @baseIssue.get 'line' + + + bindShortcuts: -> + doAction = (action) => + selectedIssueView = @getSelectedIssueEl() + return unless selectedIssueView + selectedIssueView.find(".js-issue-#{action}").click() + + key 'up', 'componentViewer', => + @options.app.controller.selectPrev() + false + + key 'down', 'componentViewer', => + @options.app.controller.selectNext() + false + + key 'left,backspace', 'componentViewer', => + @options.app.controller.closeComponentViewer() + false + + key 'f', 'componentViewer', -> doAction 'transition' + key 'a', 'componentViewer', -> doAction 'assign' + key 'm', 'componentViewer', -> doAction 'assign-to-me' + key 'p', 'componentViewer', -> doAction 'plan' + key 'i', 'componentViewer', -> doAction 'set-severity' + key 'c', 'componentViewer', -> doAction 'comment' + + + unbindShortcuts: -> + key.deleteScope 'componentViewer' + + + onClose: -> + super + @unbindScrollEvents() + @unbindShortcuts() + + + select: -> + selected = @options.app.state.get 'selectedIndex' + selectedIssue = @options.app.list.at selected + if selectedIssue.get('component') == @model.get('key') + @scrollToIssue selectedIssue.get('key') + else + @unbindShortcuts() + @options.app.controller.showComponentViewer selectedIssue + + + getSelectedIssueEl: -> + selected = @options.app.state.get 'selectedIndex' + return null unless selected? + selectedIssue = @options.app.list.at selected + return null unless selectedIssue? + selectedIssueView = @$("#issue-#{selectedIssue.get('key')}") + if selectedIssueView.length > 0 then selectedIssueView else null + + + selectIssue: (e) -> + key = $(e.currentTarget).data 'issue-key' + issue = @issues.find (issue) -> issue.get('key') == key + index = @options.app.list.indexOf issue + @options.app.state.set selectedIndex: index + + + scrollToIssue: (key) -> + el = @$("#issue-#{key}") + if el.length > 0 + line = el.closest('[data-line-number]').data 'line-number' + this.scrollToLine line + else + @unbindShortcuts() + selected = @options.app.state.get 'selectedIndex' + selectedIssue = @options.app.list.at selected + @options.app.controller.showComponentViewer selectedIssue + + + openFileByIssue: (issue) -> + @baseIssue = issue + componentKey = issue.get 'component' + componentUuid = issue.get 'componentUuid' + @open componentUuid, componentKey + + + linesLimit: -> + line = @LINES_LIMIT / 2 + if @baseIssue? && @baseIssue.has('line') + line = Math.max line, @baseIssue.get('line') + from: line - @LINES_LIMIT / 2 + 1 + to: line + @LINES_LIMIT / 2 + + + limitIssues: (issues) -> + index = @ISSUES_LIMIT / 2 + if @baseIssue? && @baseIssue.has('index') + index = Math.max index, @baseIssue.get('index') + x = issues.filter (issue) => + Math.abs(issue.get('index') - index) <= @ISSUES_LIMIT / 2 + x + + + requestIssues: -> + if @options.app.list.last().get('component') == @model.get('key') + r = @options.app.controller.fetchNextPage() + else r = $.Deferred().resolve().promise() + r.done => + @issues.reset @options.app.list.filter (issue) => issue.get('component') == @model.key() + @issues.reset @limitIssues @issues + @addIssuesPerLineMeta @issues + + + renderIssues: -> + @issues.forEach @renderIssue, @ + @$('.source-line-issues').addClass('hidden'); + + + renderIssue: (issue) -> + issueView = new IssueView + el: '#issue-' + issue.get('key') + model: issue + app: @options.app + @issueViews.push issueView + issueView.render() + + + addNextIssuesPage: -> + componentKey = @model.get 'key' + @issues.add @options.app.list.filter (issue) => issue.get('component') == componentKey + + + scrollToLine: (line) -> + row = @$("[data-line-number=#{line}]") + goal = if row.length > 0 then row.offset().top - 200 else 0 + $(window).scrollTop goal + + + closeComponentViewer: -> + @options.app.controller.closeComponentViewer() diff --git a/server/sonar-web/src/main/coffee/apps/issues/controller.coffee b/server/sonar-web/src/main/coffee/apps/issues/controller.coffee new file mode 100644 index 00000000000..18749e884a4 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/controller.coffee @@ -0,0 +1,225 @@ +# +# 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. +# + +define [ + 'components/navigator/controller' + + './component-viewer/main' + './workspace-home-view' +], ( + Controller + + ComponentViewer + HomeView +) -> + + $ = jQuery + EXTRA_FIELDS = 'actions,transitions,assigneeName,reporterName,actionPlanName' + FACET_DATA_FIELDS = ['components', 'projects', 'users', 'rules', 'actionPlans', 'languages'] + + + class extends Controller + + _facetsFromServer: -> + facets = super || [] + facets.push 'assigned_to_me' + facets + + + _issuesParameters: -> + p: @options.app.state.get 'page' + ps: @pageSize + s: 'FILE_LINE' + asc: true + extra_fields: EXTRA_FIELDS + facets: @_facetsFromServer().join() + + + _myIssuesFromResponse: (r) -> + myIssuesData = _.findWhere r.facets, property: 'assigned_to_me' + if myIssuesData? && _.isArray(myIssuesData.values) && myIssuesData.values.length > 0 + @options.app.state.set { myIssues: myIssuesData.values[0].count }, { silent: true } + else + @options.app.state.unset 'myIssues', { silent: true } + + + fetchList: (firstPage = true) -> + if firstPage + @options.app.state.set { selectedIndex: 0, page: 1 }, { silent: true } + @hideHomePage() + @closeComponentViewer() + + data = @_issuesParameters() + _.extend data, @options.app.state.get 'query' + _.extend data, @options.app.state.get 'contextQuery' if @options.app.state.get 'isContext' + + $.get "#{baseUrl}/api/issues/search", data + .done (r) => + issues = @options.app.list.parseIssues r + if firstPage + @options.app.list.reset issues + else + @options.app.list.add issues + @options.app.list.setIndex() + FACET_DATA_FIELDS.forEach (field) => @options.app.facets[field] = r[field] + @options.app.facets.reset @_allFacets() + @options.app.facets.add _.reject(r.facets, (f) -> f.property == 'assigned_to_me'), merge: true + @_myIssuesFromResponse r + @enableFacets @_enabledFacets() + @options.app.state.set + page: r.p + pageSize: r.ps + total: r.total + maxResultsReached: r.p * r.ps >= r.total + if firstPage && @isIssuePermalink() + @showComponentViewer @options.app.list.first() + + + isIssuePermalink: -> + query = @options.app.state.get('query') + query.issues? && @options.app.list.length == 1 + + + fetchFilters: -> + $.get "#{baseUrl}/api/issue_filters/app", (r) => + @options.app.state.set + canBulkChange: r.canBulkChange + canManageFilters: r.canManageFilters + @options.app.filters.reset r.favorites + + + _mergeCollections: (a, b) -> + collection = new Backbone.Collection a + collection.add b, merge: true + collection.toJSON() + + + requestFacet: (id) -> + return @requestAssigneeFacet() if id == 'assignees' + facet = @options.app.facets.get id + data = _.extend { facets: id, ps: 1 }, @options.app.state.get('query') + _.extend data, @options.app.state.get 'contextQuery' if @options.app.state.get 'isContext' + $.get "#{baseUrl}/api/issues/search", data, (r) => + FACET_DATA_FIELDS.forEach (field) => + @options.app.facets[field] = @_mergeCollections @options.app.facets[field], r[field] + facetData = _.findWhere r.facets, property: id + facet.set facetData if facetData? + + + requestAssigneeFacet: -> + facet = @options.app.facets.get 'assignees' + data = _.extend { facets: 'assignees,assigned_to_me', ps: 1 }, @options.app.state.get('query') + _.extend data, @options.app.state.get 'contextQuery' if @options.app.state.get 'isContext' + $.get "#{baseUrl}/api/issues/search", data, (r) => + FACET_DATA_FIELDS.forEach (field) => + @options.app.facets[field] = @_mergeCollections @options.app.facets[field], r[field] + facetData = _.findWhere r.facets, property: 'assignees' + @_myIssuesFromResponse r + facet.set facetData if facetData? + + + newSearch: -> + @options.app.state.unset 'filter' + @options.app.state.setQuery resolved: 'false' + + + applyFilter: (filter, ignoreQuery = false) -> + unless ignoreQuery + filterQuery = @parseQuery filter.get 'query' + @options.app.state.setQuery filterQuery + @options.app.state.set filter: filter, changed: false + + + parseQuery: -> + q = super + # Do not allow to modify the sorting + delete q.asc + delete q.s + q + + + getQuery: (separator = '|', addContext = false) -> + filter = @options.app.state.get 'query' + _.extend filter, @options.app.state.get 'contextQuery' if addContext && @options.app.state.get 'isContext' + route = [] + _.map filter, (value, property) -> + route.push '' + property + '=' + encodeURIComponent(value) + route.join separator + + + getRoute: -> + filter = @options.app.state.get 'filter' + query = super + if filter? + if @options.app.state.get('changed') && query.length > 0 + query = "id=#{filter.id}|#{query}" + else + query = "id=#{filter.id}" + query + + + _prepareComponent: (issue) -> + key: issue.get 'component' + name: issue.get 'componentLongName' + qualifier: issue.get 'componentQualifier' + project: issue.get 'project' + projectName: issue.get 'projectLongName' + + + showComponentViewer: (issue) -> + @options.app.layout.workspaceComponentViewerRegion.reset() + key.setScope 'componentViewer' + @options.app.issuesView.unbindScrollEvents() + @options.app.state.set 'component', @_prepareComponent(issue) + @options.app.componentViewer = new ComponentViewer app: @options.app + @options.app.layout.workspaceComponentViewerRegion.show @options.app.componentViewer + @options.app.layout.showComponentViewer() + @options.app.componentViewer.openFileByIssue issue + + + closeComponentViewer: -> + key.setScope 'list' + # close all popups + $('body').click() + @options.app.state.unset 'component' + @options.app.layout.workspaceComponentViewerRegion.reset() + @options.app.layout.hideComponentViewer() + @options.app.issuesView.bindScrollEvents() + @options.app.issuesView.scrollTo() + + + showHomePage: -> + @fetchList() + @options.app.layout.workspaceComponentViewerRegion.reset() + key.setScope 'home' + @options.app.issuesView.unbindScrollEvents() + @options.app.homeView = new HomeView app: @options.app + @options.app.layout.workspaceHomeRegion.show @options.app.homeView + @options.app.layout.showHomePage() + + + hideHomePage: -> + @options.app.layout.workspaceComponentViewerRegion.reset() + @options.app.layout.workspaceHomeRegion.reset() + key.setScope 'list' + @options.app.layout.hideHomePage() + @options.app.issuesView.bindScrollEvents() + @options.app.issuesView.scrollTo() + diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets-view.coffee new file mode 100644 index 00000000000..a8a17947ffd --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets-view.coffee @@ -0,0 +1,83 @@ +# +# 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. +# + +define [ + 'components/navigator/facets-view' + + './facets/base-facet' + './facets/severity-facet' + './facets/status-facet' + './facets/project-facet' + './facets/module-facet' + './facets/assignee-facet' + './facets/rule-facet' + './facets/tag-facet' + './facets/resolution-facet' + './facets/creation-date-facet' + './facets/action-plan-facet' + './facets/file-facet' + './facets/reporter-facet' + './facets/language-facet' + './facets/author-facet' + './facets/issue-key-facet' + './facets/context-facet' +], ( + FacetsView + + BaseFacet + SeverityFacet + StatusFacet + ProjectFacet + ModuleFacet + AssigneeFacet + RuleFacet + TagFacet + ResolutionFacet + CreationDateFacet + ActionPlanFacet + FileFacet + ReporterFacet + LanguageFacet + AuthorFacet + IssueKeyFacet + ContextFacet +) -> + + class extends FacetsView + + getItemView: (model) -> + switch model.get 'property' + when 'severities' then SeverityFacet + when 'statuses' then StatusFacet + when 'assignees' then AssigneeFacet + when 'resolutions' then ResolutionFacet + when 'createdAt' then CreationDateFacet + when 'projectUuids' then ProjectFacet + when 'moduleUuids' then ModuleFacet + when 'rules' then RuleFacet + when 'tags' then TagFacet + when 'actionPlans' then ActionPlanFacet + when 'fileUuids' then FileFacet + when 'reporters' then ReporterFacet + when 'languages' then LanguageFacet + when 'authors' then AuthorFacet + when 'issues' then IssueKeyFacet + when 'context' then ContextFacet + else BaseFacet diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/action-plan-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/action-plan-facet.coffee new file mode 100644 index 00000000000..a2a746e1007 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/action-plan-facet.coffee @@ -0,0 +1,72 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + $ = jQuery + + + class extends BaseFacet + template: Templates['issues-action-plan-facet'] + + + onRender: -> + super + value = @options.app.state.get('query')['planned'] + if value? && (!value || value == 'false') + @$('.js-facet').filter("[data-unplanned]").addClass 'active' + + + toggleFacet: (e) -> + unplanned = $(e.currentTarget).is "[data-unplanned]" + $(e.currentTarget).toggleClass 'active' + if unplanned + checked = $(e.currentTarget).is '.active' + value = if checked then 'false' else null + @options.app.state.updateFilter planned: value, actionPlans: null + else + @options.app.state.updateFilter planned: null, actionPlans: @getValue() + + + getValuesWithLabels: -> + values = @model.getValues() + actionPlans = @options.app.facets.actionPlans + values.forEach (v) => + key = v.val + label = null + if key + actionPlan = _.findWhere actionPlans, key: key + label = actionPlan.name if actionPlan? + v.label = label + values + + + disable: -> + @options.app.state.updateFilter planned: null, actionPlans: null + + + serializeData: -> + _.extend super, + values: @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/assignee-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/assignee-facet.coffee new file mode 100644 index 00000000000..83d0a78da80 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/assignee-facet.coffee @@ -0,0 +1,105 @@ +# +# 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. +# + +define [ + './custom-values-facet' + '../templates' +], ( + CustomValuesFacet +) -> + + $ = jQuery + + + class extends CustomValuesFacet + template: Templates['issues-assignee-facet'] + + + getUrl: -> + "#{baseUrl}/api/users/search" + + prepareAjaxSearch: -> + quietMillis: 300 + url: @getUrl() + data: (term, page) -> { q: term, p: page } + results: window.usersToSelect2 + + onRender: -> + super + value = @options.app.state.get('query')['assigned'] + if value? && (!value || value == 'false') + @$('.js-facet').filter("[data-unassigned]").addClass 'active' + + + toggleFacet: (e) -> + unassigned = $(e.currentTarget).is "[data-unassigned]" + $(e.currentTarget).toggleClass 'active' + if unassigned + checked = $(e.currentTarget).is '.active' + value = if checked then 'false' else null + @options.app.state.updateFilter assigned: value, assignees: null + else + @options.app.state.updateFilter assigned: null, assignees: @getValue() + + + getValuesWithLabels: -> + values = @model.getValues() + users = @options.app.facets.users + values.forEach (v) => + login = v.val + name = '' + if login + user = _.findWhere users, login: login + name = user.name if user? + v.label = name + values + + + disable: -> + @options.app.state.updateFilter assigned: null, assignees: null + + + addCustomValue: -> + property = @model.get 'property' + customValue = @$('.js-custom-value').select2 'val' + value = @getValue() + value += ',' if value.length > 0 + value += customValue + obj = {} + obj[property] = value + obj.assigned = null + @options.app.state.updateFilter obj + + + sortValues: (values) -> + # put "unassigned" first + _.sortBy values, (v) -> + x = if v.val == '' then -999999 else -v.count + x + + + getNumberOfMyIssues: -> + @options.app.state.get 'myIssues' + + + serializeData: -> + _.extend super, + myIssues: @getNumberOfMyIssues() + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/author-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/author-facet.coffee new file mode 100644 index 00000000000..25e8c989749 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/author-facet.coffee @@ -0,0 +1,47 @@ +# +# 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. +# + +define [ + './custom-values-facet' +], ( + CustomValuesFacet +) -> + + + class extends CustomValuesFacet + + getUrl: -> + "#{baseUrl}/api/issues/authors" + + + prepareSearch: -> + @$('.js-custom-value').select2 + placeholder: 'Search...' + minimumInputLength: 2 + allowClear: false + formatNoMatches: -> t 'select2.noMatches' + formatSearching: -> t 'select2.searching' + formatInputTooShort: -> tp 'select2.tooShort', 2 + width: '100%' + ajax: + quietMillis: 300 + url: @getUrl() + data: (term) -> { q: term, ps: 25 } + results: (data) -> { more: false, results: data.authors.map (author) -> { id: author, text: author } } diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/base-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/base-facet.coffee new file mode 100644 index 00000000000..4d41996b164 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/base-facet.coffee @@ -0,0 +1,37 @@ +# +# 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. +# + +define [ + 'components/navigator/facets/base-facet' + '../templates' +], ( + BaseFacet +) -> + + class extends BaseFacet + template: Templates['issues-base-facet'] + + onRender: -> + super + @$('[data-toggle="tooltip"]').tooltip container: 'body' + + + onClose: -> + @$('[data-toggle="tooltip"]').tooltip 'destroy' diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/context-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/context-facet.coffee new file mode 100644 index 00000000000..3809f07b856 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/context-facet.coffee @@ -0,0 +1,35 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + + class extends BaseFacet + template: Templates['issues-context-facet'] + + + serializeData: -> + _.extend super, + state: @options.app.state.toJSON() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/creation-date-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/creation-date-facet.coffee new file mode 100644 index 00000000000..c1a29019ba1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/creation-date-facet.coffee @@ -0,0 +1,141 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + $ = jQuery + + + class extends BaseFacet + template: Templates['issues-creation-date-facet'] + + + events: -> + _.extend super, + 'change input': 'applyFacet' + 'click .js-select-period-start': 'selectPeriodStart' + 'click .js-select-period-end': 'selectPeriodEnd' + + 'click .sonar-d3 rect': 'selectBar' + + 'click .js-all': 'onAllClick' + 'click .js-last-week': 'onLastWeekClick' + 'click .js-last-month': 'onLastMonthClick' + 'click .js-last-year': 'onLastYearClick' + + + onRender: -> + @$el.toggleClass 'search-navigator-facet-box-collapsed', !@model.get('enabled') + + @$('input').datepicker + dateFormat: 'yy-mm-dd' + changeMonth: true + changeYear: true + + props = ['createdAfter', 'createdBefore', 'createdAt'] + query = @options.app.state.get 'query' + props.forEach (prop) => + value = query[prop] + @$("input[name=#{prop}]").val value if value? + + values = @model.getValues() + unless _.isArray(values) && values.length > 0 + date = moment() + values = [] + for i in [0..10] + values.push count: 0, val: date.toDate().toString() + date = date.subtract 1, 'days' + values.reverse() + @$('.js-barchart').barchart values + + + selectPeriodStart: -> + @$('.js-period-start').datepicker 'show' + + + selectPeriodEnd: -> + @$('.js-period-end').datepicker 'show' + + + applyFacet: -> + obj = createdAt: null, createdInLast: null + @$('input').each -> + property = $(@).prop 'name' + value = $(@).val() + obj[property] = value + @options.app.state.updateFilter obj + + + disable: -> + @options.app.state.updateFilter + createdAfter: null + createdBefore: null + createdAt: null + createdInLast: null + + + selectBar: (e) -> + periodStart = $(e.currentTarget).data 'period-start' + periodEnd = $(e.currentTarget).data 'period-end' + @options.app.state.updateFilter + createdAfter: periodStart + createdBefore: periodEnd + createdAt: null + createdInLast: null + + + selectPeriod: (period) -> + @options.app.state.updateFilter + createdAfter: null + createdBefore: null + createdAt: null + createdInLast: period + + + onAllClick: -> + @disable() + + + onLastWeekClick: (e) -> + e.preventDefault() + @selectPeriod '1w' + + + onLastMonthClick: (e) -> + e.preventDefault() + @selectPeriod '1m' + + + onLastYearClick: (e) -> + e.preventDefault() + @selectPeriod '1y' + + + serializeData: -> + _.extend super, + periodStart: @options.app.state.get('query').createdAfter + periodEnd: @options.app.state.get('query').createdBefore + createdAt: @options.app.state.get('query').createdAt + createdInLast: @options.app.state.get('query').createdInLast diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/custom-values-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/custom-values-facet.coffee new file mode 100644 index 00000000000..9cd45d02579 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/custom-values-facet.coffee @@ -0,0 +1,71 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + + class extends BaseFacet + template: Templates['issues-custom-values-facet'] + + + events: -> + _.extend super, + 'change .js-custom-value': 'addCustomValue' + + + getUrl: -> + + + onRender: -> + super + @prepareSearch() + + + prepareSearch: -> + @$('.js-custom-value').select2 + placeholder: 'Search...' + minimumInputLength: 2 + allowClear: false + formatNoMatches: -> t 'select2.noMatches' + formatSearching: -> t 'select2.searching' + formatInputTooShort: -> tp 'select2.tooShort', 2 + width: '100%' + ajax: @prepareAjaxSearch() + + prepareAjaxSearch: -> + quietMillis: 300 + url: @getUrl() + data: (term, page) -> { s: term, p: page } + results: (data) -> { more: data.more, results: data.results } + + addCustomValue: -> + property = @model.get 'property' + customValue = @$('.js-custom-value').select2 'val' + value = @getValue() + value += ',' if value.length > 0 + value += customValue + obj = {} + obj[property] = value + @options.app.state.updateFilter obj diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/file-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/file-facet.coffee new file mode 100644 index 00000000000..62081444f4b --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/file-facet.coffee @@ -0,0 +1,56 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + $ = jQuery + + + class extends BaseFacet + template: Templates['issues-file-facet'] + + + onRender: -> + super + maxValueWidth = _.max @$('.facet-stat').map(-> $(@).outerWidth()).get() + @$('.facet-name').css 'padding-right', maxValueWidth + + + getValuesWithLabels: -> + values = @model.getValues() + source = @options.app.facets.components + values.forEach (v) => + key = v.val + label = null + if key + item = _.findWhere source, uuid: key + label = item.longName if item? + v.label = label + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/issue-key-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/issue-key-facet.coffee new file mode 100644 index 00000000000..53afcf4f441 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/issue-key-facet.coffee @@ -0,0 +1,43 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + + class extends BaseFacet + template: Templates['issues-issue-key-facet'] + + + onRender: -> + @$el.toggleClass 'hidden', !@options.app.state.get('query').issues + + + disable: -> + @options.app.state.updateFilter issues: null + + + serializeData: -> + _.extend super, + issues: @options.app.state.get('query').issues diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/language-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/language-facet.coffee new file mode 100644 index 00000000000..3d67584dd02 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/language-facet.coffee @@ -0,0 +1,67 @@ +# +# 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. +# + +define [ + './custom-values-facet' +], ( + CustomValuesFacet +) -> + + + class extends CustomValuesFacet + + getUrl: -> + "#{baseUrl}/api/languages/list" + + + prepareSearch: -> + @$('.js-custom-value').select2 + placeholder: 'Search...' + minimumInputLength: 2 + allowClear: false + formatNoMatches: -> t 'select2.noMatches' + formatSearching: -> t 'select2.searching' + formatInputTooShort: -> tp 'select2.tooShort', 2 + width: '100%' + ajax: + quietMillis: 300 + url: @getUrl() + data: (term) -> { q: term, ps: 0 } + results: (data) -> + more: false + results: data.languages.map (lang) -> { id: lang.key, text: lang.name } + + + getValuesWithLabels: -> + values = @model.getValues() + source = @options.app.facets.languages + values.forEach (v) => + key = v.val + label = null + if key + item = _.findWhere source, key: key + label = item.name if item? + v.label = label + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/module-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/module-facet.coffee new file mode 100644 index 00000000000..425f4b5c2d4 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/module-facet.coffee @@ -0,0 +1,44 @@ +# +# 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. +# + +define [ + './base-facet' +], ( + BaseFacet +) -> + + class extends BaseFacet + + getValuesWithLabels: -> + values = @model.getValues() + components = @options.app.facets.components + values.forEach (v) => + uuid = v.val + label = uuid + if uuid + component = _.findWhere components, uuid: uuid + label = component.longName if component? + v.label = label + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/project-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/project-facet.coffee new file mode 100644 index 00000000000..d7ea58a1dca --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/project-facet.coffee @@ -0,0 +1,83 @@ +# +# 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. +# + +define [ + './custom-values-facet' +], ( + CustomValuesFacet +) -> + + + class extends CustomValuesFacet + + getUrl: -> + q = @options.app.state.get 'contextComponentQualifier' + if q == 'VW' || q == 'SVW' + "#{baseUrl}/api/components/search" + else + "#{baseUrl}/api/resources/search?f=s2&q=TRK&display_uuid=true" + + + prepareSearch: -> + q = @options.app.state.get 'contextComponentQualifier' + if q == 'VW' || q == 'SVW' + @prepareSearchForViews() + else super + + + prepareSearchForViews: -> + componentUuid = this.options.app.state.get 'contextComponentUuid' + @$('.js-custom-value').select2 + placeholder: 'Search...' + minimumInputLength: 2 + allowClear: false + formatNoMatches: -> t 'select2.noMatches' + formatSearching: -> t 'select2.searching' + formatInputTooShort: -> tp 'select2.tooShort', 2 + width: '100%' + ajax: + quietMillis: 300 + url: @getUrl() + data: (term, page) -> + q: term + componentUuid: componentUuid + p: page + ps: 25 + results: (data) -> + more: data.p * data.ps < data.total, + results: data.components.map (c) -> id: c.uuid, text: c.name + + + getValuesWithLabels: -> + values = @model.getValues() + projects = @options.app.facets.projects + values.forEach (v) => + uuid = v.val + label = '' + if uuid + project = _.findWhere projects, uuid: uuid + label = project.longName if project? + v.label = label + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/reporter-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/reporter-facet.coffee new file mode 100644 index 00000000000..e8e10a4d06f --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/reporter-facet.coffee @@ -0,0 +1,54 @@ +# +# 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. +# + +define [ + './custom-values-facet' +], ( + CustomValuesFacet +) -> + + + class extends CustomValuesFacet + + getUrl: -> + "#{baseUrl}/api/users/search" + + prepareAjaxSearch: -> + quietMillis: 300 + url: @getUrl() + data: (term, page) -> { q: term, p: page } + results: window.usersToSelect2 + + getValuesWithLabels: -> + values = @model.getValues() + source = @options.app.facets.users + values.forEach (v) => + key = v.val + label = null + if key + item = _.findWhere source, login: key + label = item.name if item? + v.label = label + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/resolution-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/resolution-facet.coffee new file mode 100644 index 00000000000..7c7eef0bd74 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/resolution-facet.coffee @@ -0,0 +1,61 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + $ = jQuery + + + class extends BaseFacet + template: Templates['issues-resolution-facet'] + + + onRender: -> + super + + value = @options.app.state.get('query')['resolved'] + if value? && (!value || value == 'false') + @$('.js-facet').filter("[data-unresolved]").addClass 'active' + + + toggleFacet: (e) -> + unresolved = $(e.currentTarget).is "[data-unresolved]" + $(e.currentTarget).toggleClass 'active' + if unresolved + checked = $(e.currentTarget).is '.active' + value = if checked then 'false' else null + @options.app.state.updateFilter resolved: value, resolutions: null + else + @options.app.state.updateFilter resolved: null, resolutions: @getValue() + + + disable: -> + @options.app.state.updateFilter resolved: null, resolutions: null + + + sortValues: (values) -> + order = ['', 'FIXED', 'FALSE-POSITIVE', 'WONTFIX', 'REMOVED'] + _.sortBy values, (v) -> order.indexOf v.val + diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/rule-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/rule-facet.coffee new file mode 100644 index 00000000000..25ea9f9dd9c --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/rule-facet.coffee @@ -0,0 +1,71 @@ +# +# 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. +# + +define [ + './custom-values-facet' +], ( + CustomValuesFacet +) -> + + + class extends CustomValuesFacet + + prepareSearch: -> + url = "#{baseUrl}/api/rules/search?f=name,langName" + languages = @options.app.state.get('query').languages + if languages? + url += "&languages=#{languages}" + @$('.js-custom-value').select2 + placeholder: 'Search...' + minimumInputLength: 2 + allowClear: false + formatNoMatches: -> t 'select2.noMatches' + formatSearching: -> t 'select2.searching' + formatInputTooShort: -> tp 'select2.tooShort', 2 + width: '100%' + ajax: + quietMillis: 300 + url: url + data: (term, page) -> { q: term, p: page } + results: (data) -> + results = data.rules.map (rule) -> + id: rule.key, text: "(#{rule.langName}) #{rule.name}" + { more: (data.p * data.ps < data.total), results: results } + + + getValuesWithLabels: -> + values = @model.getValues() + rules = @options.app.facets.rules + values.forEach (v) => + key = v.val + label = '' + extra = '' + if key + rule = _.findWhere rules, key: key + label = rule.name if rule? + extra = rule.langName if rule? + v.label = label + v.extra = extra + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/severity-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/severity-facet.coffee new file mode 100644 index 00000000000..c0639ef97a6 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/severity-facet.coffee @@ -0,0 +1,36 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + + class extends BaseFacet + template: Templates['issues-severity-facet'] + + + sortValues: (values) -> + order = ['BLOCKER', 'MINOR', 'CRITICAL', 'INFO', 'MAJOR'] + _.sortBy values, (v) -> order.indexOf v.val + diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/status-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/status-facet.coffee new file mode 100644 index 00000000000..f3a0eb7a040 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/status-facet.coffee @@ -0,0 +1,35 @@ +# +# 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. +# + +define [ + './base-facet' + '../templates' +], ( + BaseFacet +) -> + + + class extends BaseFacet + template: Templates['issues-status-facet'] + + + sortValues: (values) -> + order = ['OPEN', 'RESOLVED', 'REOPENED', 'CLOSED', 'CONFIRMED'] + _.sortBy values, (v) -> order.indexOf v.val diff --git a/server/sonar-web/src/main/coffee/apps/issues/facets/tag-facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/facets/tag-facet.coffee new file mode 100644 index 00000000000..fb061cf96f8 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/facets/tag-facet.coffee @@ -0,0 +1,63 @@ +# +# 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. +# + +define [ + './custom-values-facet' +], ( + CustomValuesFacet +) -> + + + class extends CustomValuesFacet + + prepareSearch: -> + url = "#{baseUrl}/api/issues/tags?ps=10" + tags = @options.app.state.get('query').tags + if tags? + url += "&tags=#{tags}" + @$('.js-custom-value').select2 + placeholder: 'Search...' + minimumInputLength: 0 + allowClear: false + formatNoMatches: -> t 'select2.noMatches' + formatSearching: -> t 'select2.searching' + width: '100%' + ajax: + quietMillis: 300 + url: url + data: (term, page) -> { q: term, ps: 10 } + results: (data) -> + results = data.tags.map (tag) -> + id: tag, text: tag + { more: false, results: results } + + + getValuesWithLabels: -> + values = @model.getValues() + tags = @options.app.facets.tags + values.forEach (v) => + v.label = v.val + v.extra = '' + values + + + serializeData: -> + _.extend super, + values: @sortValues @getValuesWithLabels() diff --git a/server/sonar-web/src/main/coffee/apps/issues/filters-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/filters-view.coffee new file mode 100644 index 00000000000..71024317783 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/filters-view.coffee @@ -0,0 +1,97 @@ +# +# 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. +# + +define [ + './templates' +], -> + + $ = jQuery + + + class extends Marionette.ItemView + template: Templates['issues-filters'] + + + events: + 'click .js-toggle-filters': 'toggleFilters' + 'click .js-filter': 'applyFilter' + 'click .js-filter-save-as': 'saveAs' + 'click .js-filter-save': 'save' + 'click .js-filter-copy': 'copy' + 'click .js-filter-edit': 'edit' + + + initialize: (options) -> + @listenTo options.app.state, 'change:filter', @render + @listenTo options.app.state, 'change:changed', @render + @listenTo options.app.filters, 'all', @render + window.onSaveAs = window.onCopy = window.onEdit = (id) => + $('#modal').dialog 'close' + @options.app.controller.fetchFilters().done => + filter = @collection.get id + filter.fetch().done => @options.app.controller.applyFilter filter + + + onRender: -> + @$el.toggleClass 'search-navigator-filters-selected', @options.app.state.has('filter') + + + toggleFilters: (e) -> + e.stopPropagation() + @$('.search-navigator-filters-list').toggle() + $('body').on 'click.issues-filters', => + $('body').off 'click.issues-filters' + @$('.search-navigator-filters-list').hide() + + + applyFilter: (e) -> + id = $(e.currentTarget).data 'id' + filter = @collection.get id + filter.fetch().done => @options.app.controller.applyFilter filter + + + saveAs: -> + query = @options.app.controller.getQuery '&' + url = "#{baseUrl}/issues/save_as_form?#{query}" + openModalWindow url, {} + + + save: -> + query = @options.app.controller.getQuery '&' + url = "#{baseUrl}/issues/save/#{@options.app.state.get('filter').id}?#{query}" + $.post(url).done => + @options.app.state.set changed: false + + + copy: -> + url = "#{baseUrl}/issues/copy_form/#{@options.app.state.get('filter').id}" + openModalWindow url, {} + + + edit: -> + url = "#{baseUrl}/issues/edit_form/#{@options.app.state.get('filter').id}" + openModalWindow url, {} + + + serializeData: -> + _.extend super, + state: @options.app.state.toJSON() + filter: @options.app.state.get('filter')?.toJSON() + currentUser: window.SS.user diff --git a/server/sonar-web/src/main/coffee/apps/issues/issue-filter-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/issue-filter-view.coffee new file mode 100644 index 00000000000..cb3ee4d95f7 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/issue-filter-view.coffee @@ -0,0 +1,47 @@ +# +# 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. +# + +define [ + 'components/issue/views/action-options-view' + './templates' +], ( + ActionOptionsView +) -> + + $ = jQuery + + + class extends ActionOptionsView + template: Templates['issues-issue-filter-form'] + + + selectInitialOption: -> + @makeActive @getOptions().first() + + + selectOption: (e) -> + property = $(e.currentTarget).data 'property' + value = $(e.currentTarget).data 'value' + @trigger 'select', property, value + super + + + serializeData: -> + _.extend super, s: @model.get 'severity' diff --git a/server/sonar-web/src/main/coffee/apps/issues/layout.coffee b/server/sonar-web/src/main/coffee/apps/issues/layout.coffee new file mode 100644 index 00000000000..ac81d542e7c --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/layout.coffee @@ -0,0 +1,69 @@ +# +# 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. +# + +define [ + './templates' +], -> + + $ = jQuery + + + class extends Marionette.Layout + template: Templates['issues-layout'] + + + regions: + filtersRegion: '.search-navigator-filters' + facetsRegion: '.search-navigator-facets' + workspaceHeaderRegion: '.search-navigator-workspace-header' + workspaceListRegion: '.search-navigator-workspace-list' + workspaceComponentViewerRegion: '.issues-workspace-component-viewer' + workspaceHomeRegion: '.issues-workspace-home' + + + onRender: -> + @$(@filtersRegion.el).addClass('hidden') if @options.app.state.get('isContext') + $('.search-navigator').addClass 'sticky' + top = $('.search-navigator').offset().top + @$('.search-navigator-workspace-header').css top: top + @$('.search-navigator-side').css({ top: top }).isolatedScroll() + + + showSpinner: (region) -> + @[region].show new Marionette.ItemView + template: _.template('<i class="spinner"></i>') + + + showComponentViewer: -> + @scroll = $(window).scrollTop() + $('.issues').addClass 'issues-extended-view' + + + hideComponentViewer: -> + $('.issues').removeClass 'issues-extended-view' + $(window).scrollTop @scroll if @scroll? + + + showHomePage: -> + $('.issues').addClass 'issues-home-view' + + + hideHomePage: -> + $('.issues').removeClass 'issues-home-view' diff --git a/server/sonar-web/src/main/coffee/apps/issues/models/facet.coffee b/server/sonar-web/src/main/coffee/apps/issues/models/facet.coffee new file mode 100644 index 00000000000..96bc2d81e00 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/models/facet.coffee @@ -0,0 +1,37 @@ +# +# 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. +# + +define -> + + class extends Backbone.Model + idAttribute: 'property' + + + defaults: + enabled: false + + + getValues: -> + @get('values') || [] + + + toggle: -> + enabled = @get 'enabled' + @set enabled: !enabled diff --git a/server/sonar-web/src/main/coffee/apps/issues/models/facets.coffee b/server/sonar-web/src/main/coffee/apps/issues/models/facets.coffee new file mode 100644 index 00000000000..3f6a957b3d7 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/models/facets.coffee @@ -0,0 +1,28 @@ +# +# 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. +# + +define [ + './facet' +], ( + Facet +) -> + + class extends Backbone.Collection + model: Facet diff --git a/server/sonar-web/src/main/coffee/apps/issues/models/filter.coffee b/server/sonar-web/src/main/coffee/apps/issues/models/filter.coffee new file mode 100644 index 00000000000..9759bc31ff1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/models/filter.coffee @@ -0,0 +1,30 @@ +# +# 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. +# + +define -> + + class extends Backbone.Model + + url: -> + "/api/issue_filters/show/#{@id}" + + + parse: (r) -> + if r.filter? then r.filter else r diff --git a/server/sonar-web/src/main/coffee/apps/issues/models/filters.coffee b/server/sonar-web/src/main/coffee/apps/issues/models/filters.coffee new file mode 100644 index 00000000000..b002dba96a6 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/models/filters.coffee @@ -0,0 +1,28 @@ +# +# 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. +# + +define [ + './filter' +], ( + Filter +) -> + + class extends Backbone.Collection + model: Filter diff --git a/server/sonar-web/src/main/coffee/apps/issues/models/issues.coffee b/server/sonar-web/src/main/coffee/apps/issues/models/issues.coffee new file mode 100644 index 00000000000..08926040335 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/models/issues.coffee @@ -0,0 +1,95 @@ +# +# 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. +# + +define [ + 'components/issue/models/issue' +], ( + Issue +) -> + + class extends Backbone.Collection + model: Issue + + url: -> + "#{baseUrl}/api/issues/search" + + + # Used to parse /api/issues/search response + parseIssues: (r) -> + find = (source, key, keyField) -> + searchDict = {} + searchDict[keyField || 'key'] = key + _.findWhere(source, searchDict) || key + + r.issues.map (issue, index) -> + component = find r.components, issue.component + project = find r.projects, issue.project + subProject = find r.components, issue.subProject + rule = find r.rules, issue.rule + + _.extend issue, + index: index + + if component + _.extend issue, + componentUuid: component.uuid + componentLongName: component.longName + componentQualifier: component.qualifier + + if project + _.extend issue, + projectLongName: project.longName + projectUuid: project.uuid + + if subProject + _.extend issue, + subProjectLongName: subProject.longName + subProjectUuid: subProject.uuid + + if rule + _.extend issue, + ruleName: rule.name + + if _.isArray(issue.sources) && issue.sources.length > 0 + source = '' + issue.sources.forEach (line) -> + source = line[1] if line[0] == issue.line + _.extend issue, source: source + + + if _.isArray(issue.scm) && issue.scm.length > 0 + scmAuthor = '' + scmDate = '' + + issue.scm.forEach (line) -> + if line[0] == issue.line + scmAuthor = line[1] + scmDate = line[2] + + _.extend issue, + scmAuthor: scmAuthor + scmDate: scmDate + + issue + + + setIndex: -> + @forEach (issue, index) -> + issue.set index: index diff --git a/server/sonar-web/src/main/coffee/apps/issues/models/state.coffee b/server/sonar-web/src/main/coffee/apps/issues/models/state.coffee new file mode 100644 index 00000000000..b0588d25f7d --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/models/state.coffee @@ -0,0 +1,47 @@ +# +# 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. +# + +define [ + 'components/navigator/models/state' +], (State) -> + class extends State + + defaults: + page: 1 + maxResultsReached: false + query: {} + facets: ['severities', 'resolutions'] + isContext: false + + allFacets: ['issues', 'severities', 'resolutions', 'statuses', 'createdAt', 'rules', 'tags', 'projectUuids', + 'moduleUuids', 'directories', 'fileUuids', 'assignees', 'reporters', 'authors', 'languages', + 'actionPlans'], + facetsFromServer: ['severities', 'statuses', 'resolutions', 'actionPlans', 'projectUuids', 'directories', 'rules', + 'moduleUuids', 'tags', 'assignees', 'reporters', 'authors', 'fileUuids', 'languages', + 'createdAt'], + transform: { + 'resolved': 'resolutions' + 'assigned': 'assignees' + 'planned': 'actionPlans' + 'createdBefore': 'createdAt' + 'createdAfter': 'createdAt' + 'createdInLast': 'createdAt' + } + diff --git a/server/sonar-web/src/main/coffee/apps/issues/router.coffee b/server/sonar-web/src/main/coffee/apps/issues/router.coffee new file mode 100644 index 00000000000..ca220549f1f --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/router.coffee @@ -0,0 +1,58 @@ +# +# 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. +# + +define [ + 'components/navigator/router' +], ( + Router +) -> + + class extends Router + routes: + '': 'home' + ':query': 'index' + + + initialize: (options) -> + super + @listenTo options.app.state, 'change:filter', @updateRoute + + + home: -> + if @options.app.state.get 'isContext' + @navigate 'resolved=false', { trigger: true, replace: true } + else + @options.app.controller.showHomePage() + + + index: (query) -> + query = @options.app.controller.parseQuery query + if query.id? + filter = @options.app.filters.get query.id + delete query.id + filter.fetch().done => + if Object.keys(query).length > 0 + @options.app.controller.applyFilter filter, true + @options.app.state.setQuery query + @options.app.state.set changed: true + else + @options.app.controller.applyFilter filter + else + @options.app.state.setQuery query diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/_issues-filter-name.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/_issues-filter-name.hbs new file mode 100644 index 00000000000..374d15ab48f --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/_issues-filter-name.hbs @@ -0,0 +1,18 @@ +{{#if filter.name}} + {{filter.name}} + <span class="note nowrap"> + {{#unless filter.shared}} + [{{t 'issue_filter.private'}}] + {{else}} + {{#eq filter.user currentUser}} + [{{t 'issue_filter.shared_with_all_users'}}] + {{else}} + {{#if filter.user}} + [{{t 'issue_filter.shared'}}] + {{/if}} + {{/eq}} + {{/unless}} + </span> +{{else}} + {{t 'issues'}} +{{/if}} diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/_issues-facet-header.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/_issues-facet-header.hbs new file mode 100644 index 00000000000..3b57c6021ea --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/_issues-facet-header.hbs @@ -0,0 +1,4 @@ +<a class="search-navigator-facet-header js-facet-toggle"> + <i class="icon-checkbox {{#if enabled}}icon-checkbox-checked{{/if}}"></i> + {{t 'issues.facet' property}} +</a> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-action-plan-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-action-plan-facet.hbs new file mode 100644 index 00000000000..20958a58b4c --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-action-plan-facet.hbs @@ -0,0 +1,18 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#each values}} + {{#eq val ''}} + {{! unplanned }} + <a class="facet search-navigator-facet js-facet" data-unplanned title="{{t 'issue.unplanned'}}"> + <span class="facet-name">{{t 'issue.unplanned'}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{else}} + <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{label}}"> + <span class="facet-name">{{label}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/eq}} + {{/each}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-assignee-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-assignee-facet.hbs new file mode 100644 index 00000000000..9654cf06f1e --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-assignee-facet.hbs @@ -0,0 +1,30 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#notNull myIssues}} + <a class="facet search-navigator-facet js-facet" data-value="__me__" title="{{t 'me'}}"> + <span class="facet-name">{{t 'me'}}</span> + <span class="facet-stat">{{myIssues}}</span> + </a> + <hr> + {{/notNull}} + + {{#each values}} + {{#eq val ''}} + {{! unassigned }} + <a class="facet search-navigator-facet js-facet" data-unassigned title="{{t 'unassigned'}}"> + <span class="facet-name">{{t 'unassigned'}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{else}} + <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{label}}"> + <span class="facet-name">{{label}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/eq}} + {{/each}} + + <div class="search-navigator-facet-custom-value"> + <input type="hidden" class="js-custom-value"> + </div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-base-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-base-facet.hbs new file mode 100644 index 00000000000..f5b0f44f777 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-base-facet.hbs @@ -0,0 +1,10 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#each values}} + <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}"> + <span class="facet-name">{{default label val}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/each}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-context-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-context-facet.hbs new file mode 100644 index 00000000000..9f981c07c1a --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-context-facet.hbs @@ -0,0 +1,3 @@ +<div class="search-navigator-facet-query"> + Issues of {{qualifierIcon state.contextComponentQualifier}} {{state.contextComponentName}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-creation-date-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-creation-date-facet.hbs new file mode 100644 index 00000000000..4cc52cc4ae6 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-creation-date-facet.hbs @@ -0,0 +1,32 @@ +{{> '_issues-facet-header'}} + +{{#if createdAt}} + <input type="hidden" name="createdAt"> + <div class="search-navigator-facet-container"> + {{dt createdAt}} ({{fromNow createdAt}}) + </div> +{{else}} + <div class="search-navigator-facet-container"> + <div class="js-barchart" data-height="75" {{#if periodEnd}}data-end-date="{{periodEnd}}"{{/if}}></div> + <div class="search-navigator-date-facet-selection"> + <a class="js-select-period-start search-navigator-date-facet-selection-dropdown-left"> + {{#if periodStart}}{{d periodStart}}{{else}}Past{{/if}} <i class="icon-dropdown"></i> + </a> + <a class="js-select-period-end search-navigator-date-facet-selection-dropdown-right"> + {{#if periodEnd}}{{d periodEnd}}{{else}}Now{{/if}} <i class="icon-dropdown"></i> + </a> + <input class="js-period-start search-navigator-date-facet-selection-input-left" + type="text" value="{{#if periodStart}}{{ds periodStart}}{{/if}}" name="createdAfter"> + <input class="js-period-end search-navigator-date-facet-selection-input-right" + type="text" value="{{#if periodEnd}}{{ds periodEnd}}{{/if}}" name="createdBefore"> + </div> + + <div class="spacer-top"> + <span class="spacer-right">{{t 'issues.facet.createdAt.or'}}</span> + <a class="js-all spacer-right" href="#">{{t 'issues.facet.createdAt.all'}}</a> + <a class="js-last-week spacer-right {{#eq createdInLast '1w'}}active-link{{/eq}}" href="#">{{t 'issues.facet.createdAt.last_week'}}</a> + <a class="js-last-month spacer-right {{#eq createdInLast '1m'}}active-link{{/eq}}" href="#">{{t 'issues.facet.createdAt.last_month'}}</a> + <a class="js-last-year {{#eq createdInLast '1y'}}active-link{{/eq}}" href="#">{{t 'issues.facet.createdAt.last_year'}}</a> + </div> + </div> +{{/if}} diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-custom-values-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-custom-values-facet.hbs new file mode 100644 index 00000000000..c7d8a081ef1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-custom-values-facet.hbs @@ -0,0 +1,14 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#each values}} + <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{#if extra}}({{extra}}) {{/if}}{{default label val}}"> + <span class="facet-name">{{default label val}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/each}} + + <div class="search-navigator-facet-custom-value"> + <input type="hidden" class="js-custom-value"> + </div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-file-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-file-facet.hbs new file mode 100644 index 00000000000..530959b7d72 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-file-facet.hbs @@ -0,0 +1,10 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list search-navigator-facet-list-align-right"> + {{#each values}} + <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}"> + <span class="facet-name">{{default label val}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/each}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-issue-key-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-issue-key-facet.hbs new file mode 100644 index 00000000000..d68931e4487 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-issue-key-facet.hbs @@ -0,0 +1,7 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-container"> + <div class="facet search-navigator-facet active" style="cursor: default;"> + <span class="facet-name">{{issues}}</span> + </div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-resolution-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-resolution-facet.hbs new file mode 100644 index 00000000000..08c1b25a15a --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-resolution-facet.hbs @@ -0,0 +1,20 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#each values}} + {{#eq val ''}} + {{! unresolved }} + <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-unresolved + title="{{t 'issue.unresolved.description'}}" data-toggle="tooltip" data-placement="right"> + <span class="facet-name">{{t 'unresolved'}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{else}} + <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" + title="{{t 'issue.resolution' val 'description'}}" data-toggle="tooltip" data-placement="right"> + <span class="facet-name">{{t 'issue.resolution' val}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/eq}} + {{/each}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-severity-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-severity-facet.hbs new file mode 100644 index 00000000000..96a6470ef72 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-severity-facet.hbs @@ -0,0 +1,11 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#each values}} + <a class="facet search-navigator-facet search-navigator-facet-half js-facet" + data-value="{{val}}" title="{{t 'severity' val 'description'}}" data-toggle="tooltip" data-placement="right"> + <span class="facet-name">{{severityIcon val}} {{t 'severity' val}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/each}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-status-facet.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-status-facet.hbs new file mode 100644 index 00000000000..33e556abf5e --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/facets/issues-status-facet.hbs @@ -0,0 +1,11 @@ +{{> '_issues-facet-header'}} + +<div class="search-navigator-facet-list"> + {{#each values}} + <a class="facet search-navigator-facet search-navigator-facet-half js-facet" + data-value="{{val}}" title="{{t 'issue.status' val 'description'}}" data-toggle="tooltip" data-placement="right"> + <span class="facet-name">{{statusIcon val}} {{t 'issue.status' val}}</span> + <span class="facet-stat">{{numberShort count}}</span> + </a> + {{/each}} +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-filters.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-filters.hbs new file mode 100644 index 00000000000..a197f5335d1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-filters.hbs @@ -0,0 +1,55 @@ +<h1 class="page-title dropdown"> + {{#if state.canManageFilters}} + <a class="search-navigator-filters-show-list dropdown-toggle" data-toggle="dropdown"> + <i class="icon-list"></i><span class="issues-filters-name">{{> '_issues-filter-name'}}</span> + </a> + <ul class="dropdown-menu"> + {{#each items}} + <li> + <a class="search-navigator-filters-button search-navigator-filters-filter js-filter" data-id="{{id}}"> + {{name}} + </a> + </li> + {{/each}} + {{#notEmpty items}} + <li class="divider"></li> + {{/notEmpty}} + <li> + <a class="search-navigator-filters-manage" href="{{link '/issues/manage'}}">{{t 'manage'}}</a> + </li> + </ul> + {{#if filter.description}} + <div class="search-navigator-filters-description">{{filter.description}}</div> + {{/if}} + {{else}} + <span class="search-navigator-filters-name">{{t 'issues'}}</span> + {{/if}} +</h1> + +<div class="page-actions"> + <div class="button-group"> + {{#if state.canManageFilters}} + {{#if filter.canModify}} + {{#if state.changed}} + <button class="js-filter-save" id="issues-filter-save">{{t 'save'}}</button> + {{/if}} + {{/if}} + + {{#unless filter.id}} + <button class="js-filter-save-as" id="issues-filter-save-as">{{t 'save_as'}}</button> + {{/unless}} + + {{#if filter.id}} + {{#unless state.changed}} + <button class="js-filter-copy" id="issues-filter-copy">{{t 'copy'}}</button> + {{/unless}} + {{/if}} + + {{#if filter.canModify}} + {{#if filter.id}} + <button class="js-filter-edit" id="issues-filter-edit">{{t 'edit'}}</button> + {{/if}} + {{/if}} + {{/if}} + </div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-issue-filter-form.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-issue-filter-form.hbs new file mode 100644 index 00000000000..01515749698 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-issue-filter-form.hbs @@ -0,0 +1,71 @@ +<h6>{{t 'issue.filter_similar_issues'}}</h6> + +<div class="issue-action-options"> + <a href="#" class="issue-action-option" data-property="severities" data-value="{{s}}"> + {{severityIcon severity}} {{t 'severity' severity}} + </a> + + <a href="#" class="issue-action-option" data-property="statuses" data-value="{{status}}"> + {{statusIcon status}} {{t 'issue.status' status}} + </a> + + {{#if resolution}} + <a href="#" class="issue-action-option" data-property="resolutions" data-value="{{resolution}}"> + {{t 'issue.resolution' resolution}} + </a> + {{else}} + <a href="#" class="issue-action-option" data-property="resolved" data-value="false"> + {{t 'unresolved'}} + </a> + {{/if}} + + {{#if assignee}} + <a href="#" class="issue-action-option" data-property="assignees" data-value="{{assignee}}"> + {{t 'assigned_to'}} {{assigneeName}} + </a> + {{else}} + <a href="#" class="issue-action-option" data-property="assigned" data-value="false"> + {{t 'unassigned'}} + </a> + {{/if}} + + {{#if actionPlan}} + <a href="#" class="issue-action-option" data-property="actionPlans" data-value="{{actionPlan}}"> + {{t 'issue.planned_for'}} {{actionPlanName}} + </a> + {{else}} + <a href="#" class="issue-action-option" data-property="planned" data-value="false"> + {{t 'issue.unplanned'}} + </a> + {{/if}} + + <hr> + + <a href="#" class="issue-action-option" data-property="rules" data-value="{{rule}}"> + {{limitString ruleName}} + </a> + + {{#each tags}} + <a href="#" class="issue-action-option" data-property="tags" data-value="{{this}}"> + <i class="icon-tags icon-half-transparent"></i> {{this}} + </a> + {{/each}} + + <hr> + + <a href="#" class="issue-action-option" data-property="projectUuids" data-value="{{projectUuid}}"> + {{qualifierIcon 'TRK'}} {{projectLongName}} + </a> + + {{#if subProject}} + <a href="#" class="issue-action-option" data-property="moduleUuids" data-value="{{subProjectUuid}}"> + {{qualifierIcon 'BRC'}} {{subProjectLongName}} + </a> + {{/if}} + + <a href="#" class="issue-action-option" data-property="fileUuids" data-value="{{componentUuid}}"> + {{qualifierIcon componentQualifier}} {{fileFromPath componentLongName}} + </a> +</div> + +<div class="bubble-popup-arrow"></div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-issue-filter.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-issue-filter.hbs new file mode 100644 index 00000000000..875bc3bc4a5 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-issue-filter.hbs @@ -0,0 +1,5 @@ +<div class="issue-meta"> + <a class="issue-action issue-action-with-options js-issue-filter" href="#"> + <i class="icon-filter icon-half-transparent"></i> <i class="icon-dropdown"></i> + </a> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-layout.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-layout.hbs new file mode 100644 index 00000000000..5a61d1f66bf --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-layout.hbs @@ -0,0 +1,11 @@ +<div class="search-navigator-side"> + <div class="search-navigator-filters"></div> + <div class="search-navigator-facets"></div> +</div> + +<div class="search-navigator-workspace"> + <div class="search-navigator-workspace-header"></div> + <div class="search-navigator-workspace-list"></div> + <div class="issues-workspace-component-viewer"></div> + <div class="issues-workspace-home"></div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-header.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-header.hbs new file mode 100644 index 00000000000..4b4958fd1d1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-header.hbs @@ -0,0 +1,37 @@ +<div class="issues-header-component nowrap"> + {{#if state.component}} + <a class="js-back">{{t 'issues.return_to_list'}}</a> + + {{#with state.component}} + {{qualifierIcon 'TRK'}} <a href="{{dashboardUrl project}}" title="{{projectName}}">{{projectName}}</a> + + {{qualifierIcon qualifier}} <a href="{{dashboardUrl key}}" title="{{name}}">{{name}}</a> + {{/with}} + {{else}} + + {{/if}} +</div> + + +<div class="search-navigator-header-actions"> + {{#notNull state.total}} + <div class="search-navigator-header-pagination"> + {{#gt state.total 0}} + <a class="js-prev icon-prev" title="{{t 'paging_previous'}}"></a> + <span class="current">{{sum state.selectedIndex 1}} / <span id="issues-total">{{state.total}}</span></span> + <a class="js-next icon-next" title="{{t 'paging_next'}}"></a> + {{else}} + <span class="current">0 / <span id="issues-total">0</span></span> + {{/gt}} + </div> + {{/notNull}} + + + <div class="search-navigator-header-buttons button-group"> + <button id="issues-reload" class="js-reload">{{t 'reload'}}</button> + <button class="js-new-search" id="issues-new-search">{{t 'issue_filter.new_search'}}</button> + {{#if state.canBulkChange}} + <button id="issues-bulk-change" class="js-bulk-change">{{t 'bulk_change'}}</button> + {{/if}} + </div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-home.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-home.hbs new file mode 100644 index 00000000000..3889dcdd978 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-home.hbs @@ -0,0 +1,77 @@ +<div class="spacer-top spacer-bottom"> + <div class="columns"> + <div class="column-half {{#unless user}}column-one{{/unless}}"> + <h3 class="text-center">{{t 'issues.home.recent_issues'}}</h3> + <p class="note text-center">({{t 'issues.home.over_last_week'}})</p> + + <div class="spacer-top text-center js-barchart" data-height="75" data-width="300"></div> + <h4 class="spacer-top spacer-bottom text-center">{{t 'issues.home.projects'}}</h4> + <table class="data zebra spacer-top"> + {{#each projects}} + <tr> + <td>{{qualifierIcon 'TRK'}} <a href="{{issuesHomeLink 'projectUuids' val}}">{{label}}</a></td> + <td class="thin text-right">+{{numberShort count}}</td> + </tr> + {{/each}} + </table> + <h4 class="spacer-top spacer-bottom text-center">{{t 'issues.home.authors'}}</h4> + <table class="data zebra spacer-top"> + {{#each authors}} + <tr> + <td><a href="{{issuesHomeLink 'authors' val}}">{{val}}</a></td> + <td class="thin text-right">+{{numberShort count}}</td> + </tr> + {{/each}} + </table> + <h4 class="spacer-top spacer-bottom text-center">{{t 'issues.home.tags'}}</h4> + <ul class="list-inline"> + {{#each tags}} + <li><a class="link-no-underline" style="font-size: {{size}}px;" data-toggle="tooltip" data-placement="bottom" + href="{{issuesHomeLink 'tags' val}}" + title="+{{numberShort count}}">{{val}}</a></li> + {{/each}} + </ul> + </div> + + {{#if user}} + <div class="column-half"> + <h3 class="text-center">{{t 'issues.home.my_recent_issues'}}</h3> + <p class="note text-center">({{t 'issues.home.over_last_week'}})</p> + + <div class="spacer-top text-center js-my-barchart" data-height="75" data-width="300"></div> + {{#notEmpty myProjects}} + <h4 class="spacer-top spacer-bottom text-center">{{t 'issues.home.projects'}}</h4> + <table class="data zebra spacer-top"> + {{#each myProjects}} + <tr> + <td>{{qualifierIcon 'TRK'}} <a href="{{myIssuesHomeLink 'projectUuids' val}}">{{label}}</a></td> + <td class="thin text-right">+{{numberShort count}}</td> + </tr> + {{/each}} + </table> + {{/notEmpty}} + {{#notEmpty myTags}} + <h4 class="spacer-top spacer-bottom text-center">{{t 'issues.home.tags'}}</h4> + <ul class="list-inline"> + {{#each myTags}} + <li><a class="link-no-underline" style="font-size: {{size}}px;" data-toggle="tooltip" data-placement="bottom" + href="{{myIssuesHomeLink 'tags' val}}" + title="+{{numberShort count}}">{{val}}</a></li> + {{/each}} + </ul> + {{/notEmpty}} + {{#notEmpty filters}} + <h3 class="spacer-bottom text-center" style="padding-top: 12px; margin-top: 20px; border-top: 1px solid #efefef;"> + {{t 'issues.home.my_filters'}}</h3> + <ul class="list-inline"> + {{#each filters}} + <li> + <a href="{{issueFilterHomeLink id}}">{{name}}</a> + </li> + {{/each}} + </ul> + {{/notEmpty}} + </div> + {{/if}} + </div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-list-component.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-list-component.hbs new file mode 100644 index 00000000000..d5d0b439952 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-list-component.hbs @@ -0,0 +1,13 @@ +<div class="issues-workspace-list-component"> + <a class="issues-workspace-list-component-part" href="{{dashboardUrl project}}"> + {{qualifierIcon 'TRK'}} {{projectLongName}} + </a> + {{#if subProject}} + <a class="issues-workspace-list-component-part" href="{{dashboardUrl subProject}}"> + {{qualifierIcon 'TRK'}} {{subProjectLongName}} + </a> + {{/if}} + <a class="issues-workspace-list-component-part" href="{{dashboardUrl component}}"> + {{qualifierIcon componentQualifier}} {{componentLongName}} + </a> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-list.hbs b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-list.hbs new file mode 100644 index 00000000000..37421cb75c2 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/templates/issues-workspace-list.hbs @@ -0,0 +1,5 @@ +<div class="js-list"></div> + +<div class="search-navigator-workspace-list-more js-more"> + <i class="spinner"></i> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/issues/workspace-header-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/workspace-header-view.coffee new file mode 100644 index 00000000000..7672d1ac41c --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/workspace-header-view.coffee @@ -0,0 +1,64 @@ +# +# 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. +# + +define [ + 'components/navigator/workspace-header-view' + './templates' +], ( + WorkspaceHeaderView +) -> + + $ = jQuery + + + class extends WorkspaceHeaderView + template: Templates['issues-workspace-header'] + + + events: -> + _.extend super, + 'click .js-back': 'returnToList' + 'click .js-new-search': 'newSearch' + + + initialize: -> + super + @_onBulkIssues = window.onBulkIssues + window.onBulkIssues = => + $('#modal').dialog 'close' + @options.app.controller.fetchList() + + + onClose: -> + window.onBulkIssues = @_onBulkIssues + + + returnToList: -> + @options.app.controller.closeComponentViewer() + + + newSearch: -> + @options.app.controller.newSearch() + + + bulkChange: -> + query = @options.app.controller.getQuery '&', true + url = "#{baseUrl}/issues/bulk_change_form?#{query}" + openModalWindow url, {} diff --git a/server/sonar-web/src/main/coffee/apps/issues/workspace-home-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/workspace-home-view.coffee new file mode 100644 index 00000000000..6bf9c15fcee --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/workspace-home-view.coffee @@ -0,0 +1,149 @@ +# +# 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. +# + +define [ + 'widgets/issue-filter/widget' + './templates' +], (IssueFilter) -> + + $ = jQuery + + + Handlebars.registerHelper 'issuesHomeLink', (property, value) -> + "#{baseUrl}/issues/search#resolved=false|createdInLast=1w|#{property}=#{encodeURIComponent value}" + + Handlebars.registerHelper 'myIssuesHomeLink', (property, value) -> + "#{baseUrl}/issues/search#resolved=false|createdInLast=1w|assignees=__me__|#{property}=#{encodeURIComponent value}" + + Handlebars.registerHelper 'issueFilterHomeLink', (id) -> + "#{baseUrl}/issues/search#id=#{id}" + + + class extends Marionette.ItemView + template: Templates['issues-workspace-home'] + + + modelEvents: + 'change': 'render' + + + events: + 'click .js-barchart rect': 'selectBar' + 'click .js-my-barchart rect': 'selectMyBar' + + + initialize: -> + @model = new Backbone.Model + @requestIssues() + @requestMyIssues() + + + _getProjects: (r) -> + projectFacet = _.findWhere r.facets, property: 'projectUuids' + if projectFacet? + values = _.head projectFacet.values, 3 + values.forEach (v) => + project = _.findWhere r.projects, uuid: v.val + v.label = project.longName + values + + + _getAuthors: (r) -> + authorFacet = _.findWhere r.facets, property: 'authors' + if authorFacet? + values = _.head authorFacet.values, 3 + values + + + _getTags: (r) -> + MIN_SIZE = 10 + MAX_SIZE = 24 + tagFacet = _.findWhere r.facets, property: 'tags' + if tagFacet? + values = _.head tagFacet.values, 10 + minCount = _.min(values, (v) -> v.count).count + maxCount = _.max(values, (v) -> v.count).count + scale = d3.scale.linear().domain([minCount, maxCount]).range([MIN_SIZE, MAX_SIZE]) + values.forEach (v) => + v.size = scale v.count + values + + + requestIssues: -> + url = "#{baseUrl}/api/issues/search" + options = + resolved: false + createdInLast: '1w' + ps: 1 + facets: 'createdAt,projectUuids,authors,tags' + $.get(url, options).done (r) => + @model.set + createdAt: _.findWhere(r.facets, property: 'createdAt')?.values + projects: @_getProjects r + authors: @_getAuthors r + tags: @_getTags r + + + requestMyIssues: -> + url = "#{baseUrl}/api/issues/search" + options = + resolved: false + createdInLast: '1w' + assignees: '__me__' + ps: 1 + facets: 'createdAt,projectUuids,authors,tags' + $.get(url, options).done (r) => + @model.set + myCreatedAt: _.findWhere(r.facets, property: 'createdAt')?.values + myProjects: @_getProjects r + myTags: @_getTags r + + + onRender: -> + values = @model.get 'createdAt' + myValues = @model.get 'myCreatedAt' + @$('.js-barchart').barchart values if values? + @$('.js-my-barchart').barchart myValues if myValues? + @$('[data-toggle="tooltip"]').tooltip container: 'body' + + + selectBar: (e) -> + periodStart = $(e.currentTarget).data 'period-start' + periodEnd = $(e.currentTarget).data 'period-end' + @options.app.state.setQuery + resolved: false + createdAfter: periodStart + createdBefore: periodEnd + + + selectMyBar: (e) -> + periodStart = $(e.currentTarget).data 'period-start' + periodEnd = $(e.currentTarget).data 'period-end' + @options.app.state.setQuery + resolved: false + assignees: '__me__' + createdAfter: periodStart + createdBefore: periodEnd + + + serializeData: -> + _.extend super, + user: window.SS.user + filters: _.sortBy @options.app.filters.toJSON(), 'name' diff --git a/server/sonar-web/src/main/coffee/apps/issues/workspace-list-empty-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/workspace-list-empty-view.coffee new file mode 100644 index 00000000000..23bba0eef47 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/workspace-list-empty-view.coffee @@ -0,0 +1,28 @@ +# +# 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. +# + +define -> + + class extends Marionette.ItemView + className: 'search-navigator-no-results' + + + template: -> + t 'issue_filter.no_issues' diff --git a/server/sonar-web/src/main/coffee/apps/issues/workspace-list-item-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/workspace-list-item-view.coffee new file mode 100644 index 00000000000..62b223fb57f --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/workspace-list-item-view.coffee @@ -0,0 +1,118 @@ +# +# 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. +# + +define [ + 'components/issue/issue-view' + './issue-filter-view' + './templates' +], ( + IssueView + IssueFilterView +) -> + + $ = jQuery + + SHOULD_NULL = + any: ['issues'] + resolutions: ['resolved'] + resolved: ['resolutions'] + assignees: ['assigned'] + assigned: ['assignees'] + actionPlans: ['planned'] + planned: ['actionPlans'] + + class extends IssueView + filterTemplate: Templates['issues-issue-filter'] + + events: -> + _.extend super, + 'click': 'selectCurrent' + 'dblclick': 'openComponentViewer' + 'click .js-issue-navigate': 'openComponentViewer' + 'click .js-issue-filter': 'onIssueFilterClick' + + + initialize: (options) -> + super + @listenTo options.app.state, 'change:selectedIndex', @select + + + onRender: -> + super + @select() + @addFilterSelect() + @$el.addClass 'issue-navigate-right' + + + onIssueFilterClick: (e) -> + e.preventDefault() + e.stopPropagation() + $('body').click() + @popup = new IssueFilterView + triggerEl: $(e.currentTarget) + bottomRight: true + model: @model + @popup.on 'select', (property, value) => + obj = {} + obj[property] = '' + value + SHOULD_NULL.any.forEach (p) -> obj[p] = null + if SHOULD_NULL[property]? + SHOULD_NULL[property].forEach (p) -> obj[p] = null + @options.app.state.updateFilter obj + @popup.close() + @popup.render() + + + + addFilterSelect: -> + @$('.issue-table-meta-cell-first').find('.issue-meta-list').append @filterTemplate @model.toJSON() + + + select: -> + selected = @model.get('index') == @options.app.state.get 'selectedIndex' + @$el.toggleClass 'selected', selected + + + selectCurrent: -> + @options.app.state.set selectedIndex: @model.get('index') + + + resetIssue: (options) -> + key = @model.get 'key' + componentUuid = @model.get 'componentUuid' + index = @model.get 'index' + @model.clear silent: true + @model.set { key: key, componentUuid: componentUuid, index: index }, { silent: true } + @model.fetch(options) + .done => + @trigger 'reset' + + + openComponentViewer: -> + @options.app.state.set selectedIndex: @model.get('index') + if @options.app.state.has 'component' + @options.app.controller.closeComponentViewer() + else + @options.app.controller.showComponentViewer @model + + + serializeData: -> + _.extend super, + showComponent: true diff --git a/server/sonar-web/src/main/coffee/apps/issues/workspace-list-view.coffee b/server/sonar-web/src/main/coffee/apps/issues/workspace-list-view.coffee new file mode 100644 index 00000000000..889b03310a2 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/issues/workspace-list-view.coffee @@ -0,0 +1,103 @@ +# +# 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. +# + +define [ + 'components/navigator/workspace-list-view' + './workspace-list-item-view' + './workspace-list-empty-view' + './templates' +], ( + WorkspaceListView + IssueView + EmptyView +) -> + + $ = jQuery + + COMPONENT_HEIGHT = 29 + BOTTOM_OFFSET = 10 + + + class extends WorkspaceListView + template: Templates['issues-workspace-list'] + componentTemplate: Templates['issues-workspace-list-component'] + itemView: IssueView + itemViewContainer: '.js-list' + emptyView: EmptyView + + + bindShortcuts: -> + doAction = (action) => + selectedIssue = @collection.at @options.app.state.get 'selectedIndex' + return unless selectedIssue? + selectedIssueView = @children.findByModel selectedIssue + selectedIssueView.$(".js-issue-#{action}").click() + + super + + key 'right', 'list', => + selectedIssue = @collection.at @options.app.state.get 'selectedIndex' + @options.app.controller.showComponentViewer selectedIssue + return false + + key 'f', 'list', -> doAction 'transition' + key 'a', 'list', -> doAction 'assign' + key 'm', 'list', -> doAction 'assign-to-me' + key 'p', 'list', -> doAction 'plan' + key 'i', 'list', -> doAction 'set-severity' + key 'c', 'list', -> doAction 'comment' + key 't', 'list', -> doAction 'edit-tags' + + + scrollTo: -> + selectedIssue = @collection.at @options.app.state.get 'selectedIndex' + return unless selectedIssue? + selectedIssueView = @children.findByModel selectedIssue + parentTopOffset = @$el.offset().top + viewTop = selectedIssueView.$el.offset().top - parentTopOffset + if selectedIssueView.$el.prev().is('.issues-workspace-list-component') + viewTop -= COMPONENT_HEIGHT + viewBottom = selectedIssueView.$el.offset().top + selectedIssueView.$el.outerHeight() + BOTTOM_OFFSET + windowTop = $(window).scrollTop() + windowBottom = windowTop + $(window).height() + if viewTop < windowTop + $(window).scrollTop viewTop + if viewBottom > windowBottom + $(window).scrollTop $(window).scrollTop() - windowBottom + viewBottom + + + appendHtml: (compositeView, itemView, index) -> + $container = this.getItemViewContainer compositeView + model = @collection.at(index) + if model? + prev = @collection.at(index - 1) + putComponent = !prev? + if prev? + fullComponent = [model.get('project'), model.get('component')].join ' ' + fullPrevComponent = [prev.get('project'), prev.get('component')].join ' ' + putComponent = true unless fullComponent == fullPrevComponent + if putComponent + $container.append @componentTemplate model.toJSON() + $container.append itemView.el + + + closeChildren: -> + super + @$('.issues-workspace-list-component').remove() diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/app.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/app.coffee new file mode 100644 index 00000000000..770d1f1e454 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/app.coffee @@ -0,0 +1,117 @@ +# +# 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. +# +define [ + './collections/quality-gates', + './views/quality-gate-sidebar-list-view', + './views/quality-gate-actions-view', + './views/quality-gate-edit-view', + './router', + './layout' +], (QualityGates, + QualityGateSidebarListItemView, + QualityGateActionsView, + QualityGateEditView, + QualityGateRouter, + QualityGateLayout) -> + + # Create a Quality Gate Application + App = new Marionette.Application + + + App.qualityGates = new QualityGates + + + App.openFirstQualityGate = -> + App.layout.detailsRegion.reset() + + + App.deleteQualityGate = (id) -> + App.qualityGates.remove id + App.openFirstQualityGate() + + + App.unsetDefaults = (id) -> + App.qualityGates.each (gate) -> + gate.set('default', false) unless gate.id == id + + + # Construct layout + App.addInitializer -> + @layout = new QualityGateLayout app: @ + jQuery('#quality-gates').append @layout.render().el + jQuery('#footer').addClass 'search-navigator-footer' + + + # Construct actions bar + App.addInitializer -> + @codingRulesHeaderView = new QualityGateActionsView + app: @ + @layout.actionsRegion.show @codingRulesHeaderView + + + # Construct sidebar + App.addInitializer -> + @qualityGateSidebarListView = new QualityGateSidebarListItemView + collection: @qualityGates + app: @ + @layout.resultsRegion.show @qualityGateSidebarListView + + + # Construct edit view + App.addInitializer -> + @qualityGateEditView = new QualityGateEditView app: @ + @qualityGateEditView.render() + + + # Start router + App.addInitializer -> + @router = new QualityGateRouter app: @ + + QUALITY_GATES = '/quality_gates' + path = window.location.pathname + pos = path.indexOf QUALITY_GATES + root = path.substr(0, pos + QUALITY_GATES.length) + Backbone.history.start pushState: true, root: root + + + # Open first quality gate when come to the page + App.addInitializer -> + initial = Backbone.history.fragment == '' + App.openFirstQualityGate() if initial + + + # Call app, Load metrics and the list of quality gates before start the application + appXHR = jQuery.ajax + url: "#{baseUrl}/api/qualitygates/app" + .done (r) => + App.canEdit = r.edit + App.periods = r.periods + App.metrics = r.metrics + + qualityGatesXHR = App.qualityGates.fetch() + + # Message bundles + l10nXHR = window.requestMessages() + + jQuery.when(qualityGatesXHR, appXHR, l10nXHR) + .done -> + # Start the application + App.start() + diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/collections/conditions.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/collections/conditions.coffee new file mode 100644 index 00000000000..a3ecccc29d1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/collections/conditions.coffee @@ -0,0 +1,29 @@ +# +# 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. +# + +define [ + '../models/condition' +], ( + Condition +) -> + + class Conditions extends Backbone.Collection + model: Condition + comparator: 'metric' diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/collections/quality-gates.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/collections/quality-gates.coffee new file mode 100644 index 00000000000..c74a50c4a97 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/collections/quality-gates.coffee @@ -0,0 +1,48 @@ +# +# 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. +# + +define [ + '../models/quality-gate' +], ( + QualityGate +) -> + + class QualityGates extends Backbone.Collection + model: QualityGate + + + url: -> + "#{baseUrl}/api/qualitygates/list" + + + # { + # "qualitygates": [ + # { "id": 42, "name": "QG 1" }, + # { "id": 43, "name": "QG 2" }, + # { "id": 44, "name": "QG 3" } + # ], + # "default": 42 + # } + parse: (r) -> + r.qualitygates.map (gate) -> + _.extend gate, default: gate.id == r.default + + + comparator: (item) -> item.get('name').toLowerCase() diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/layout.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/layout.coffee new file mode 100644 index 00000000000..36da66f1941 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/layout.coffee @@ -0,0 +1,42 @@ +# +# 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. +# + +define [ + './templates' +], -> + + $ = jQuery + + class AppLayout extends Marionette.Layout + template: Templates['quality-gates-layout'] + + + regions: + headerRegion: '.search-navigator-workspace-header' + actionsRegion: '.search-navigator-filters' + resultsRegion: '.quality-gates-results' + detailsRegion: '.search-navigator-workspace-details' + + + onRender: -> + $('.search-navigator').addClass 'sticky search-navigator-extended-view' + top = $('.search-navigator').offset().top + @$('.search-navigator-workspace-header').css top: top + @$('.search-navigator-side').css({ top: top }).isolatedScroll() diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/models/condition.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/models/condition.coffee new file mode 100644 index 00000000000..7cf8ca03b82 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/models/condition.coffee @@ -0,0 +1,58 @@ +# +# 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. +# + +define -> + + class Condition extends Backbone.Model + + url: -> + "#{baseUrl}/api/qualitygates/create_condition" + + + save: -> + method = unless @isNew() then 'update' else 'create' + data = + metric: @get('metric').key + op: @get('op') + warning: @get('warning') + error: @get('error') + + unless @get('period') == '0' + data.period = @get('period') + + unless @isNew() + data.id = @id + else + data.gateId = @get('gateId') + + jQuery.ajax({ + url: "#{baseUrl}/api/qualitygates/#{method}_condition" + type: 'POST' + data: data + }).done (r) => + @set 'id', r.id + + + delete: -> + jQuery.ajax + url: "#{baseUrl}/api/qualitygates/delete_condition" + type: 'POST' + data: id: @id + diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/models/quality-gate.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/models/quality-gate.coffee new file mode 100644 index 00000000000..3b6dc6d1f41 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/models/quality-gate.coffee @@ -0,0 +1,26 @@ +# +# 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. +# + +define -> + + class QualityGate extends Backbone.Model + + url: -> + "#{baseUrl}/api/qualitygates/show?id=#{@get('id')}" diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/router.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/router.coffee new file mode 100644 index 00000000000..31fc35abe68 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/router.coffee @@ -0,0 +1,62 @@ +# +# 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. +# + +define [ + './models/quality-gate', + './views/quality-gate-detail-view', + './views/quality-gate-detail-header-view', +], ( + QualityGate, + QualityGateDetailView, + QualityGateDetailHeaderView +) -> + + class QualityGateRouter extends Backbone.Router + + routes: + '': 'index' + 'show/:id': 'show' + + + initialize: (options) -> + @app = options.app + + + index: -> + + + show: (id) -> + qualityGate = @app.qualityGates.get id + if qualityGate + @app.qualityGateSidebarListView.highlight id + + qualityGateDetailHeaderView = new QualityGateDetailHeaderView + app: @app + model: qualityGate + @app.layout.headerRegion.show qualityGateDetailHeaderView + + qualityGateDetailView = new QualityGateDetailView + app: @app + model: qualityGate + @app.layout.detailsRegion.show qualityGateDetailView + qualityGateDetailView.$el.hide() + + qualityGate.fetch().done -> + qualityGateDetailView.$el.show() diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/_quality-gate-intro.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/_quality-gate-intro.hbs new file mode 100644 index 00000000000..6f194fb7fbb --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/_quality-gate-intro.hbs @@ -0,0 +1,7 @@ +<div class=""> + <p class="spacer-bottom">Quality Gates are collections of simple boolean thresholds set on project measures. A project + must pass each of the thresholds in order to pass the Quality Gate as a whole.</p> + + <p>It is possible to set a default Quality Gate, which will be applied to all projects not explicitly assigned to some + other gate.</p> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-actions.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-actions.hbs new file mode 100644 index 00000000000..6826aa94353 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-actions.hbs @@ -0,0 +1,8 @@ +<h1 class="page-title">{{t 'quality_gates.page'}}</h1> +{{#if canEdit}} + <div class="page-actions"> + <div class="button-group"> + <button id="quality-gate-add">{{t 'create'}}</button> + </div> + </div> +{{/if}} diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-condition.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-condition.hbs new file mode 100644 index 00000000000..9be26807f78 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-condition.hbs @@ -0,0 +1,62 @@ +<td nowrap> + {{metric.name}} + {{#if metric.hidden}} + <span class="deprecated">{{t 'deprecated'}}</span> + {{/if}} +</td> +<td width="20%" nowrap> + {{#if canEdit}} + <select name="period" style="width: 100%"> + {{#unless isDiffMetric}}<option value="0">{{t 'value'}}</option>{{/unless}} + {{#each periods}}<option value="{{key}}">Δ {{text}}</option>{{/each}} + </select> + {{else}} + {{#if periodText}}Δ {{periodText}} + {{else}}{{t 'value'}} + {{/if}} + {{/if}} +</td> +<td width="10%" nowrap> + {{#if canEdit}} + <select name="operator"> + {{#operators metric.type}} + <option value="{{this}}">{{t 'quality_gates.operator' this}}</option> + {{/operators}} + </select> + {{else}} + {{t 'quality_gates.operator' op}} + {{/if}} +</td> +<td width="1" class="nowrap"> + <i class="icon-alert-warn" title="{{t 'quality_gates.warning_tooltip'}}"></i> + {{#if canEdit}} + <input name="warning" class="input-small" data-type="{{metric.type}}" placeholder="{{metric.placeholder}}" + type="text"> + {{else}} + {{warning}} + {{/if}} +</td> +<td width="1" class="nowrap"> + <i class="icon-alert-error" title="{{t 'quality_gates.error_tooltip'}}"></i> + {{#if canEdit}} + <input name="error" class="input-small" data-type="{{metric.type}}" placeholder="{{metric.placeholder}}" + type="text"> + {{else}} + {{error}} + {{/if}} +</td> +<td class="quality-gate-condition-actions" width="120px" nowrap> + {{#if canEdit}} + {{#if id}} + <div class="button-group"> + <button class="update-condition" disabled>{{t 'update_verb'}}</button> + <button class="button-red delete-condition">{{t 'delete'}}</button> + </div> + {{else}} + <div class="button-group"> + <button class="add-condition">{{t 'add_verb'}}</button> + <a class="action cancel-add-condition">{{t 'cancel'}}</a> + </div> + {{/if}} + {{/if}} +</td> diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-conditions-empty.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-conditions-empty.hbs new file mode 100644 index 00000000000..40c92668496 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-conditions-empty.hbs @@ -0,0 +1,3 @@ +<td colspan="6"> + {{t 'quality_gates.no_conditions'}} +</td>
\ No newline at end of file diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-conditions.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-conditions.hbs new file mode 100644 index 00000000000..74888876431 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-conditions.hbs @@ -0,0 +1,45 @@ +<div class="quality-gate-section-name">{{t 'quality_gates.conditions'}}</div> + +<div class="quality-gate-introduction"> + <p>{{t 'quality_gates.introduction'}} + <a class="link-action quality-gate-introduction-show-more">{{t 'more'}}</a> + </p> + <div class="quality-gate-introduction-more inline-help"> + {{t 'quality_gates.health_icons'}} + <ul> + <li> + <i class="icon-alert-ok"></i> + {{t 'alerts.notes.ok'}} + </li> + <li> + <i class="icon-alert-warn"></i> + {{t 'alerts.notes.warn'}} + </li> + <li> + <i class="icon-alert-error"></i> + {{t 'alerts.notes.error'}} + </li> + </ul> + </div> +</div> + +{{#if canEdit}} + <div class="quality-gate-new-condition"> + <label for="quality-gate-new-condition-metric">{{t 'quality_gates.add_condition'}}:</label> + <select id="quality-gate-new-condition-metric"> + <option></option> + {{#each metricGroups}} + <optgroup label="{{domain}}"> + {{#each metrics}}<option value="{{key}}">{{name}}</option>{{/each}} + </optgroup> + {{/each}} + </select> + </div> +{{/if}} + +<div class="quality-gate-conditions-wrap"> + <table class="data zebra width100 marginbottom10 spaced quality-gate-conditions"> + <thead><tr></tr></thead> + <tbody></tbody> + </table> +</div>
\ No newline at end of file diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-header.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-header.hbs new file mode 100644 index 00000000000..71f7e3b06de --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-header.hbs @@ -0,0 +1,16 @@ +<h2 class="search-navigator-header-component">{{name}}</h2> + +{{#if canEdit}} + <div class="search-navigator-header-actions"> + <div class="button-group"> + <button id="quality-gate-rename">{{t 'rename'}}</button> + <button id="quality-gate-copy">{{t 'copy'}}</button> + {{#if default}} + <button id="quality-gate-unset-as-default">{{t 'unset_as_default'}}</button> + {{else}} + <button id="quality-gate-set-as-default">{{t 'set_as_default'}}</button> + {{/if}} + <button id="quality-gate-delete" class="button-red">{{t 'delete'}}</button> + </div> + </div> +{{/if}} diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-projects.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-projects.hbs new file mode 100644 index 00000000000..989cae0f31e --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail-projects.hbs @@ -0,0 +1,13 @@ +<div class="quality-gate-section-name">{{t 'quality_gates.projects'}}</div> + +{{#if default}} + <p class="quality-gate-default-message"> + {{#if canEdit}} + {{t 'quality_gates.projects_for_default.edit'}} + {{else}} + {{t 'quality_gates.projects_for_default'}} + {{/if}} + </p> +{{else}} + <div id="select-list-projects"></div> +{{/if}}
\ No newline at end of file diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail.hbs new file mode 100644 index 00000000000..0c5467b3476 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-detail.hbs @@ -0,0 +1,2 @@ +<div id="quality-gate-conditions" class="quality-gate-section"></div> +<div id="quality-gate-projects" class="quality-gate-section"></div>
\ No newline at end of file diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-edit.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-edit.hbs new file mode 100644 index 00000000000..5aeb891a816 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-edit.hbs @@ -0,0 +1,22 @@ +<form> + <div class="modal-head"> + {{#if method}} + <h2>{{t 'quality_gates' method }}</h2> + {{/if}} + </div> + + <div class="modal-body"> + <div class="alert alert-danger"></div> + <div class="modal-field"> + <label for="quality-gate-edit-name">{{t 'name'}} <em class="mandatory">*</em></label> + <input id="quality-gate-edit-name" type="text" size="50" maxlength="100" value="{{name}}"> + </div> + </div> + + <div class="modal-foot"> + {{#eq method "rename"}}<button>{{t 'save'}}</button>{{/eq}} + {{#eq method "copy"}}<button>{{t 'copy'}}</button>{{/eq}} + {{#eq method "create"}}<button>{{t 'create'}}</button>{{/eq}} + <a id="quality-gate-cancel-create" class="action">{{t 'cancel'}}</a> + </div> +</form> diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-sidebar-list-empty.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-sidebar-list-empty.hbs new file mode 100644 index 00000000000..8b017f09987 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-sidebar-list-empty.hbs @@ -0,0 +1 @@ +<div class="line line-nowrap">{{t 'quality_gates.noQualityGates'}}</div>
\ No newline at end of file diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-sidebar-list-item.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-sidebar-list-item.hbs new file mode 100644 index 00000000000..2e92b2eedde --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gate-sidebar-list-item.hbs @@ -0,0 +1,13 @@ +<table> + <tr> + <td class="text-top">{{name}}</td> + <td class="text-top thin nowrap spacer-left"> + {{#if default}} + <span class="badge pull-right">{{t 'default'}}</span> + {{/if}} + </td> + </tr> +</table> + + + diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gates-layout.hbs b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gates-layout.hbs new file mode 100644 index 00000000000..3428ac4d466 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/templates/quality-gates-layout.hbs @@ -0,0 +1,9 @@ +<div class="search-navigator-side search-navigator-side-light"> + <div class="search-navigator-filters"></div> + <div class="quality-gates-results panel"></div> +</div> + +<div class="search-navigator-workspace"> + <div class="search-navigator-workspace-header"> </div> + <div class="search-navigator-workspace-details">{{> '_quality-gate-intro'}}</div> +</div> diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-actions-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-actions-view.coffee new file mode 100644 index 00000000000..46e5f3e6d99 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-actions-view.coffee @@ -0,0 +1,44 @@ +# +# 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. +# + +define [ + '../models/quality-gate' + '../templates' +], ( + QualityGate +) -> + + class QualityGateActionsView extends Marionette.ItemView + template: Templates['quality-gate-actions'] + + + events: + 'click #quality-gate-add': 'add' + + + add: -> + qualityGate = new QualityGate() + @options.app.qualityGateEditView.method = 'create' + @options.app.qualityGateEditView.model = qualityGate + @options.app.qualityGateEditView.show() + + + serializeData: -> + _.extend super, canEdit: @options.app.canEdit diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-condition-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-condition-view.coffee new file mode 100644 index 00000000000..54c106126e2 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-condition-view.coffee @@ -0,0 +1,146 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class QualityGateDetailConditionView extends Marionette.ItemView + tagName: 'tr' + template: Templates['quality-gate-detail-condition'] + spinner: '<i class="spinner"></i>' + + + modelEvents: + 'change:id': 'render' + + + ui: + periodSelect: '[name=period]' + operatorSelect: '[name=operator]' + warningInput: '[name=warning]' + errorInput: '[name=error]' + actionsBox: '.quality-gate-condition-actions' + updateButton: '.update-condition' + deleteButton: '.delete-condition' + + + events: + 'click @ui.updateButton': 'saveCondition' + 'click @ui.deleteButton': 'deleteCondition' + 'click .add-condition': 'saveCondition' + 'click .cancel-add-condition': 'cancelAddCondition' + 'keyup :input': 'enableUpdate' + 'change :input': 'enableUpdate' + + + initialize: -> + @populateMetric() + + + populateMetric: -> + metricKey = @model.get('metric') + metric = _.findWhere @options.app.metrics, key: metricKey + if metric? + switch metric.type + when 'WORK_DUR' then metric.placeholder = '1d 7h 59min' + when 'RATING' then metric.placeholder = 'A' + @model.set { metric: metric }, { silent: true } + @model.set { isDiffMetric: metric.key.indexOf('new_') == 0 }, { silent: true } + + + onRender: -> + @ui.periodSelect.val @model.get('period') || '0' + @ui.operatorSelect.val @model.get('op') + @ui.warningInput.val @model.get('warning') + @ui.errorInput.val @model.get('error') + + @ui.periodSelect.select2 + allowClear: false + minimumResultsForSearch: 999 + width: '100%' + + @ui.operatorSelect.select2 + allowClear: false + minimumResultsForSearch: 999 + width: '150px' + + @ui.periodSelect.select2('open') if @model.isNew() + + + showSpinner: -> + jQuery(@spinner).prependTo @ui.actionsBox + @ui.actionsBox.find(':not(.spinner)').hide() + + + hideSpinner: -> + @ui.actionsBox.find('.spinner').remove() + @ui.actionsBox.find(':not(.spinner)').show() + + + saveCondition: -> + @showSpinner() + @model.set + period: @ui.periodSelect.val() + op: @ui.operatorSelect.val() + warning: @ui.warningInput.val() + error: @ui.errorInput.val() + @model.save() + .always => + @ui.updateButton.prop 'disabled', true + @hideSpinner() + .done => + @options.collectionView.updateConditions() + + + deleteCondition: -> + confirmDialog + title: t 'quality_gates.delete_condition' + html: tp 'quality_gates.delete_condition.confirm.message', @model.get('metric').name + yesLabel: t 'delete' + noLabel: t 'cancel' + yesHandler: => + @showSpinner() + @model.delete().done => + @options.collectionView.collection.remove @model + @options.collectionView.updateConditions() + @close() + always: => @ui.deleteButton.blur() + + + cancelAddCondition: -> + @close() + + + enableUpdate: -> + @ui.updateButton.prop 'disabled', false + + + serializeData: -> + period = _.findWhere(@options.app.periods, key: this.model.get('period')) + data = _.extend super, + canEdit: @options.app.canEdit + periods: @options.app.periods + periodText: period?.text + unless @options.app.canEdit + _.extend data, + warning: jQuery('<input>').data('type', @model.get('metric').type).val(@model.get('warning')).originalVal() + error: jQuery('<input>').data('type', @model.get('metric').type).val(@model.get('error')).originalVal() + data diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-conditions-empty-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-conditions-empty-view.coffee new file mode 100644 index 00000000000..b285ca05617 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-conditions-empty-view.coffee @@ -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. +# + +define [ + '../templates' +], -> + + class QualityGateDetailConditionsView extends Marionette.ItemView + tagName: 'tr' + template: Templates['quality-gate-detail-conditions-empty'] diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-conditions-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-conditions-view.coffee new file mode 100644 index 00000000000..29843cbf32c --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-conditions-view.coffee @@ -0,0 +1,105 @@ +# +# 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. +# + +define [ + '../models/condition', + './quality-gate-detail-condition-view', + './quality-gate-detail-conditions-empty-view' + '../templates' +], ( + Condition, + QualityGateDetailConditionView, + QualityGateDetailConditionsEmptyView, +) -> + + class QualityGateDetailConditionsView extends Marionette.CompositeView + template: Templates['quality-gate-detail-conditions'] + itemView: QualityGateDetailConditionView + emptyView: QualityGateDetailConditionsEmptyView + itemViewContainer: '.quality-gate-conditions tbody' + + + ui: + metricSelect: '#quality-gate-new-condition-metric' + introductionShowMore: '.quality-gate-introduction-show-more' + introductionMore: '.quality-gate-introduction-more' + + + events: + 'click @ui.introductionShowMore': 'showMoreIntroduction' + 'change @ui.metricSelect': 'addCondition' + + + itemViewOptions: -> + app: @options.app + collectionView: @ + + + appendHtml: (compositeView, itemView) -> + if (compositeView.isBuffering) + compositeView.elBuffer.appendChild itemView.el + compositeView._bufferedChildren.push itemView + else + container = @getItemViewContainer compositeView + container.prepend itemView.el + + + onRender: -> + @ui.introductionMore.hide() + @ui.metricSelect.select2 + allowClear: false, + width: '250px', + placeholder: t('alerts.select_metric') + + + groupedMetrics: -> + metrics = @options.app.metrics + metrics = _.filter metrics, (metric) -> + !metric.hidden + metrics = _.groupBy metrics, 'domain' + metrics = _.map metrics, (metrics, domain) -> + domain: domain, metrics: _.sortBy metrics, 'short_name' + _.sortBy metrics, 'domain' + + + serializeData: -> + _.extend super, + canEdit: @options.app.canEdit + metricGroups: @groupedMetrics() + + + showMoreIntroduction: -> + @ui.introductionShowMore.hide() + @ui.introductionMore.show() + + + addCondition: -> + metric = @ui.metricSelect.val() + @ui.metricSelect.select2('val', '') + condition = new Condition + metric: metric + gateId: @options.gateId + @collection.unshift condition + + + updateConditions: -> + conditions = @collection.map (item) -> _.extend item.toJSON(), + metric: item.get('metric').key + @options.qualityGate.set { conditions: conditions }, { silent: true } diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-header-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-header-view.coffee new file mode 100644 index 00000000000..1980b9ed7c2 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-header-view.coffee @@ -0,0 +1,101 @@ +# +# 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. +# + +define [ + '../models/quality-gate' + '../templates', +], ( + QualityGate +) -> + + class QualityGateDetailHeaderView extends Marionette.ItemView + template: Templates['quality-gate-detail-header'] + spinner: '<i class="spinner"></i>' + + + modelEvents: + 'change': 'render' + + + ui: + deleteButton: '#quality-gate-delete' + + + events: + 'click #quality-gate-rename': 'renameQualityGate' + 'click #quality-gate-copy': 'copyQualityGate' + 'click @ui.deleteButton': 'deleteQualityGate' + 'click #quality-gate-set-as-default': 'setAsDefault' + 'click #quality-gate-unset-as-default': 'unsetAsDefault' + + + renameQualityGate: -> + @options.app.qualityGateEditView.method = 'rename' + @options.app.qualityGateEditView.model = @model + @options.app.qualityGateEditView.show() + + + copyQualityGate: -> + copiedModel = new QualityGate @model.toJSON() + copiedModel.set 'default', false + @options.app.qualityGateEditView.method = 'copy' + @options.app.qualityGateEditView.model = copiedModel + @options.app.qualityGateEditView.show() + + + deleteQualityGate: -> + message = if @model.get 'default' then 'quality_gates.delete.confirm.default' else 'quality_gates.delete.confirm.message' + message = tp message, @model.get('name') + confirmDialog + title: t 'quality_gates.delete' + html: message + yesLabel: t 'delete' + noLabel: t 'cancel' + yesHandler: => + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualitygates/destroy" + data: id: @model.id + .done => @options.app.deleteQualityGate @model.id + always: => @ui.deleteButton.blur() + + + changeDefault: (set) -> + data = if set then { id: @model.id } else {} + method = if set then 'set_as_default' else 'unset_default' + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualitygates/#{method}" + data: data + .done => + @options.app.unsetDefaults @model.id + @model.set 'default', !@model.get('default') + + + setAsDefault: -> + @changeDefault true + + + unsetAsDefault: -> + @changeDefault false + + + serializeData: -> + _.extend super, canEdit: @options.app.canEdit diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-projects-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-projects-view.coffee new file mode 100644 index 00000000000..726d95ac5c9 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-projects-view.coffee @@ -0,0 +1,55 @@ +# +# 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. +# + +define [ + 'components/common/select-list' + '../templates' +], -> + + class QualityGateDetailProjectsView extends Marionette.ItemView + template: Templates['quality-gate-detail-projects'] + + + onRender: -> + unless @model.get('default') + new SelectList + el: @$('#select-list-projects') + width: '100%' + readOnly: !@options.app.canEdit + focusSearch: false + format: (item) -> item.name + searchUrl: "#{baseUrl}/api/qualitygates/search?gateId=#{@options.gateId}" + selectUrl: "#{baseUrl}/api/qualitygates/select" + deselectUrl: "#{baseUrl}/api/qualitygates/deselect" + extra: + gateId: @options.gateId + selectParameter: 'projectId' + selectParameterValue: 'id' + labels: + selected: t('quality_gates.projects.with') + deselected: t('quality_gates.projects.without') + all: t('quality_gates.projects.all') + noResults: t('quality_gates.projects.noResults') + tooltips: + select: t('quality_gates.projects.select_hint') + deselect: t('quality_gates.projects.deselect_hint') + + serializeData: -> + _.extend super, canEdit: @options.app.canEdit diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-view.coffee new file mode 100644 index 00000000000..10b4b6e0ceb --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-detail-view.coffee @@ -0,0 +1,67 @@ +# +# 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. +# + +define [ + '../collections/conditions', + './quality-gate-detail-header-view', + './quality-gate-detail-conditions-view', + './quality-gate-detail-projects-view' + '../templates', +], ( + Conditions, + QualityGateDetailHeaderView, + QualityGateDetailConditionsView, + QualityGateDetailProjectsView +) -> + + class QualityGateDetailView extends Marionette.Layout + template: Templates['quality-gate-detail'] + + + regions: + conditionsRegion: '#quality-gate-conditions' + projectsRegion: '#quality-gate-projects' + + + modelEvents: + 'change': 'render' + + + onRender: -> + @showConditions() + @showProjects() + + + showConditions: -> + conditions = new Conditions @model.get('conditions') + view = new QualityGateDetailConditionsView + app: @options.app + collection: conditions + gateId: @model.id + qualityGate: @model + @conditionsRegion.show view + + + showProjects: -> + view = new QualityGateDetailProjectsView + app: @options.app + model: @model + gateId: @model.id + @projectsRegion.show view diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-edit-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-edit-view.coffee new file mode 100644 index 00000000000..67adfeca477 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-edit-view.coffee @@ -0,0 +1,101 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class QualityGateEditView extends Marionette.ItemView + template: Templates['quality-gate-edit'] + + + ui: + nameInput: '#quality-gate-edit-name' + + + events: + 'submit form': 'onSubmit' + 'click #quality-gate-cancel-create': 'hide' + + + onRender: -> + @$el.dialog + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + + + show: -> + @render() + @$el.dialog 'open' + @ui.nameInput.focus() + + + hide: -> + @$el.dialog 'close' + + + saveRequest: (data) -> + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualitygates/#{@method}" + data: data + .done => @hide() + + + onSubmit: (e) -> + e.preventDefault() + switch @method + when 'create' then @createQualityGate() + when 'copy' then @copyQualityGate() + when 'rename' then @saveQualityGate() + else + + + createQualityGate: -> + data = name: @ui.nameInput.val() + @saveRequest(data).done (r) => + @model.set id: r.id, name: r.name + @options.app.qualityGates.add @model + @options.app.router.navigate "show/#{r.id}", trigger: true + + + saveQualityGate: -> + data = id: @model.id, name: @ui.nameInput.val() + @saveRequest(data).done (r) => + @model.set name: r.name + + + copyQualityGate: -> + data = id: @model.id, name: @ui.nameInput.val() + @saveRequest(data).done (r) => + @model.set id: r.id, name: r.name + @options.app.qualityGates.add @model + @options.app.router.navigate "show/#{r.id}", trigger: true + + + serializeData: -> + if @model + _.extend @model.toJSON(), method: @method diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-empty-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-empty-view.coffee new file mode 100644 index 00000000000..9ec9393dd9e --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-empty-view.coffee @@ -0,0 +1,28 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class QualityGateSidebarListEmptyView extends Marionette.ItemView + tagName: 'li' + className: 'empty' + template: Templates['quality-gate-sidebar-list-empty'] diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-item-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-item-view.coffee new file mode 100644 index 00000000000..3527a6c6e1a --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-item-view.coffee @@ -0,0 +1,44 @@ +# +# 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. +# + +define [ + '../templates' +], -> + + class QualityGateSidebarListItemView extends Marionette.ItemView + tagName: 'a' + className: 'list-group-item' + template: Templates['quality-gate-sidebar-list-item'] + + + modelEvents: + 'change': 'render' + + + events: + 'click': 'showQualityGate' + + + onRender: -> + @$el.toggleClass 'active', @options.highlighted + + + showQualityGate: -> + @options.app.router.navigate "show/#{@model.id}", trigger: true diff --git a/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-view.coffee b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-view.coffee new file mode 100644 index 00000000000..7fd40da3121 --- /dev/null +++ b/server/sonar-web/src/main/coffee/apps/quality-gate/views/quality-gate-sidebar-list-view.coffee @@ -0,0 +1,42 @@ +# +# 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. +# + +define [ + './quality-gate-sidebar-list-item-view', + './quality-gate-sidebar-list-empty-view' +], ( + QualityGateSidebarListItemView, + QualityGateSidebarListEmptyView, +) -> + + class QualityGateSidebarListView extends Marionette.CollectionView + className: 'list-group' + itemView: QualityGateSidebarListItemView + emptyView: QualityGateSidebarListEmptyView + + + itemViewOptions: (model) -> + app: @options.app + highlighted: model.get('id') == +@highlighted + + + highlight: (id) -> + @highlighted = id + @render() |