diff options
17 files changed, 164 insertions, 93 deletions
diff --git a/server/sonar-web/src/main/coffee/issue/issue-view.coffee b/server/sonar-web/src/main/coffee/issue/issue-view.coffee index 24ea55f22de..a747345efd2 100644 --- a/server/sonar-web/src/main/coffee/issue/issue-view.coffee +++ b/server/sonar-web/src/main/coffee/issue/issue-view.coffee @@ -252,3 +252,10 @@ define [ ruleOverlay = new RuleOverlay model: new Backbone.Model r.rule ruleOverlay.render() + + + serializeData: -> + componentKey = encodeURIComponent @model.get 'component' + issueKey = encodeURIComponent @model.get 'key' + _.extend super, + permalink: "#{baseUrl}/component/index#component=#{componentKey}¤tIssue=#{issueKey}" diff --git a/server/sonar-web/src/main/coffee/issue/views/more-actions-view.coffee b/server/sonar-web/src/main/coffee/issue/views/more-actions-view.coffee index 8322e90a61c..19d3a72a688 100644 --- a/server/sonar-web/src/main/coffee/issue/views/more-actions-view.coffee +++ b/server/sonar-web/src/main/coffee/issue/views/more-actions-view.coffee @@ -6,8 +6,6 @@ define [ PopupView ) -> - $ = jQuery - class extends PopupView template: Templates['issue-more-actions'] @@ -20,10 +18,3 @@ define [ action: (e) -> actionKey = $(e.currentTarget).data 'action' @options.detailView.action actionKey - - - serializeData: -> - componentKey = encodeURIComponent @model.get 'component' - issueKey = encodeURIComponent @model.get 'key' - _.extend super, - permalink: "#{baseUrl}/component/index#component=#{componentKey}¤tIssue=#{issueKey}" diff --git a/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee b/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee index e3143ceebdd..098e878aa45 100644 --- a/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee +++ b/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee @@ -157,7 +157,6 @@ define [ requestIssues: -> - console.log 'Request issues' if @options.app.issues.last().get('component') == @model.get('key') r = @options.app.controller.fetchNextPage() else r = $.Deferred().resolve().promise() @@ -165,7 +164,6 @@ define [ @issues.reset @options.app.issues.filter (issue) => issue.get('component') == @model.key() @issues.reset @limitIssues @issues @addIssuesPerLineMeta @issues - console.log 'Issues loaded' renderIssue: (issue) -> diff --git a/server/sonar-web/src/main/coffee/issues/controller.coffee b/server/sonar-web/src/main/coffee/issues/controller.coffee index 6d8d43b094f..1e2a5800e58 100644 --- a/server/sonar-web/src/main/coffee/issues/controller.coffee +++ b/server/sonar-web/src/main/coffee/issues/controller.coffee @@ -210,6 +210,8 @@ define [ closeComponentViewer: -> key.setScope 'list' + # close all popups + $('body').click() @options.app.state.unset 'component' @options.app.layout.workspaceComponentViewerRegion.reset() @options.app.layout.hideComponentViewer() diff --git a/server/sonar-web/src/main/hbs/issue/issue-more-actions.hbs b/server/sonar-web/src/main/hbs/issue/issue-more-actions.hbs index 396ee6f6764..18917b5f9c1 100644 --- a/server/sonar-web/src/main/hbs/issue/issue-more-actions.hbs +++ b/server/sonar-web/src/main/hbs/issue/issue-more-actions.hbs @@ -1,7 +1,4 @@ <ul class="issue-more-actions"> - <li> - <a class="issue-action" target="_blank" href="{{permalink}}">Get Permalink</a> - </li> {{#pluginActions actions}} <li> <a class="issue-action js-issue-action" data-action="{{this}}">{{t "issue.action" this "formlink"}}</a> diff --git a/server/sonar-web/src/main/hbs/issue/issue.hbs b/server/sonar-web/src/main/hbs/issue/issue.hbs index 96b761442ae..bd0d0724550 100644 --- a/server/sonar-web/src/main/hbs/issue/issue.hbs +++ b/server/sonar-web/src/main/hbs/issue/issue.hbs @@ -28,10 +28,13 @@ <div class="issue-meta"> {{#inArray actions "assign"}} <a class="issue-action issue-action-with-options js-issue-assign"> - <span class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span> <i class="icon-dropdown"></i> + <span + class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span> <i + class="icon-dropdown"></i> </a> {{else}} - <span class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span> + <span + class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span> {{/inArray}} </div> @@ -42,10 +45,13 @@ <div class="issue-meta"> {{#inArray actions "plan"}} <a class="issue-action issue-action-with-options js-issue-plan"> - <span class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span> <i class="icon-dropdown"></i> + <span + class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span> <i + class="icon-dropdown"></i> </a> {{else}} - <span class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span> + <span + class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span> {{/inArray}} </div> @@ -55,11 +61,13 @@ </div> {{/inArray}} - <div class="issue-meta"> - <a class="issue-action issue-action-with-options js-issue-more"> - <span class="issue-meta-label">{{t 'more'}}</span> <i class="icon-dropdown"></i> - </a> - </div> + {{#ifHasExtraActions actions}} + <div class="issue-meta"> + <a class="issue-action issue-action-with-options js-issue-more"> + <span class="issue-meta-label">{{t 'more'}}</span> <i class="icon-dropdown"></i> + </a> + </div> + {{/ifHasExtraActions}} <div class="issue-meta issue-meta-on-right"> <a class="issue-action issue-action-with-options js-issue-show-changelog" title="{{dt creationDate}}"> @@ -77,11 +85,15 @@ <a class="issue-action js-issue-rule">Rule</a> </div> - {{#if line}} - <div class="issue-meta issue-meta-in-corner"> + + <div class="issue-meta issue-meta-in-corner"> + {{#if line}} <span class="issue-meta-label">L{{line}}</span> - </div> - {{/if}} + + {{/if}} + <a class="issue-action js-issue-permalink icon-link" href="{{permalink}}" target="_blank"></a> + </div> + </div> {{#notEmpty comments}} diff --git a/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs b/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs index 91480af86e2..d693e1d1bb5 100644 --- a/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs +++ b/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs @@ -4,7 +4,7 @@ {{#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}} diff --git a/server/sonar-web/src/main/hbs/source-viewer/source-viewer-coverage-popup.hbs b/server/sonar-web/src/main/hbs/source-viewer/source-viewer-coverage-popup.hbs index be7d99c755a..cea9ae48f3c 100644 --- a/server/sonar-web/src/main/hbs/source-viewer/source-viewer-coverage-popup.hbs +++ b/server/sonar-web/src/main/hbs/source-viewer/source-viewer-coverage-popup.hbs @@ -1,5 +1,17 @@ <div class="bubble-popup-container"> - <div class="bubble-popup-title">{{t 'component_viewer.transition.coverage'}}</div> + <div class="bubble-popup-title"> + {{#if row.lineHits}} + {{t 'source_viewer.covered'}} + {{#if row.conditions}} + ({{default row.coveredConditions 0}} of {{row.conditions}} {{t 'source_viewer.conditions'}}) + {{/if}} + {{else}} + {{t 'source_viewer.not_covered'}} + {{#if row.conditions}} + ({{row.conditions}} {{t 'source_viewer.conditions'}}) + {{/if}} + {{/if}} + </div> {{#each testFiles}} <div class="bubble-popup-section"> diff --git a/server/sonar-web/src/main/hbs/source-viewer/source-viewer-scm-popup.hbs b/server/sonar-web/src/main/hbs/source-viewer/source-viewer-scm-popup.hbs new file mode 100644 index 00000000000..9eef858a15f --- /dev/null +++ b/server/sonar-web/src/main/hbs/source-viewer/source-viewer-scm-popup.hbs @@ -0,0 +1,13 @@ +<div class="bubble-popup-container"> + <div class="bubble-popup-section"> + {{scmAuthor}} + </div> + <div class="bubble-popup-section"> + {{dt scmDate}} + </div> + <div class="bubble-popup-section"> + {{scmRevision}} + </div> +</div> + +<div class="bubble-popup-arrow"></div> diff --git a/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs b/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs index 3d56acd24a2..2d1cd025d60 100644 --- a/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs +++ b/server/sonar-web/src/main/hbs/source-viewer/source-viewer.hbs @@ -7,23 +7,24 @@ <tr class="source-line {{#eq line 0}}{{#empty issues}}hidden{{/empty}}{{/eq}}"> <td class="source-meta source-line-number" {{#if line}}data-line-number="{{line}}"{{/if}}></td> - <td class="source-meta source-line-scm"> + <td class="source-meta source-line-scm" {{#if line}}data-line-number="{{line}}"{{/if}}> {{#ifSCMChanged2 ../source line}} <div class="source-line-scm-inner" title="{{scmAuthor}} {{scmDate}}" data-author="{{scmAuthor}}"></div> {{/ifSCMChanged2}} </td> - <td class="source-meta source-line-coverage {{#notNull covered}}source-line-{{covered}}{{/notNull}}" + <td class="source-meta source-line-coverage {{#notNull coverageStatus}}source-line-{{coverageStatus}}{{/notNull}}" data-line-number="{{line}}"> <div class="source-line-bar"></div> </td> - <td class="source-meta source-line-duplications {{#if duplicated}}source-line-duplicated{{/if}}"> + <td class="source-meta source-line-duplications {{#if duplicated}}source-line-duplicated{{/if}}" + title="{{t 'source_viewer.expand_duplications'}}"> <div class="source-line-bar"></div> </td> {{#each duplications}} - <td class="source-meta source-line-duplications-extra hidden {{#if this}}source-line-duplicated{{/if}}" + <td class="source-meta source-line-duplications-extra {{#if this}}source-line-duplicated{{/if}}" data-index="{{this}}" data-line-number="{{line}}"> <div class="source-line-bar"></div> </td> diff --git a/server/sonar-web/src/main/js/source-viewer/popups/coverage-popup.js b/server/sonar-web/src/main/js/source-viewer/popups/coverage-popup.js index de6e419937d..c4ca335d066 100644 --- a/server/sonar-web/src/main/js/source-viewer/popups/coverage-popup.js +++ b/server/sonar-web/src/main/js/source-viewer/popups/coverage-popup.js @@ -2,8 +2,7 @@ define([ 'backbone.marionette', 'templates/source-viewer', 'common/popup', - 'component-viewer/utils' -], function (Marionette, Templates, Popup, utils) { +], function (Marionette, Templates, Popup) { var $ = jQuery; @@ -36,7 +35,10 @@ define([ tests: testSet }; }); - return { testFiles: testFiles }; + return { + testFiles: testFiles, + row: this.options.row + }; } }); }); diff --git a/server/sonar-web/src/main/js/source-viewer/popups/duplication-popup.js b/server/sonar-web/src/main/js/source-viewer/popups/duplication-popup.js index b0677415c13..3dc6ef6a715 100644 --- a/server/sonar-web/src/main/js/source-viewer/popups/duplication-popup.js +++ b/server/sonar-web/src/main/js/source-viewer/popups/duplication-popup.js @@ -1,7 +1,7 @@ define([ 'backbone.marionette', 'templates/component-viewer', - 'common/popup', + 'common/popup' ], function (Marionette, Templates, Popup) { var $ = jQuery; diff --git a/server/sonar-web/src/main/js/source-viewer/popups/scm-popup.js b/server/sonar-web/src/main/js/source-viewer/popups/scm-popup.js new file mode 100644 index 00000000000..c727c79f2a7 --- /dev/null +++ b/server/sonar-web/src/main/js/source-viewer/popups/scm-popup.js @@ -0,0 +1,23 @@ +define([ + 'backbone.marionette', + 'templates/source-viewer', + 'common/popup', +], function (Marionette, Templates, Popup) { + + return Popup.extend({ + template: Templates['source-viewer-scm-popup'], + + events: { + 'click': 'onClick' + }, + + onRender: function () { + Popup.prototype.onRender.apply(this, arguments); + this.$('.bubble-popup-container').isolatedScroll(); + }, + + onClick: function (e) { + e.stopPropagation(); + } + }); +}); diff --git a/server/sonar-web/src/main/js/source-viewer/viewer.js b/server/sonar-web/src/main/js/source-viewer/viewer.js index 491a14b5527..48c31943112 100644 --- a/server/sonar-web/src/main/js/source-viewer/viewer.js +++ b/server/sonar-web/src/main/js/source-viewer/viewer.js @@ -6,6 +6,7 @@ define([ 'issue/models/issue', 'issue/collections/issues', 'issue/issue-view', + 'source-viewer/popups/scm-popup', 'source-viewer/popups/coverage-popup', 'source-viewer/popups/duplication-popup', 'source-viewer/popups/line-actions-popup' @@ -17,15 +18,13 @@ define([ Issue, Issues, IssueView, + SCMPopupView, CoveragePopupView, DuplicationPopupView, LineActionsPopupView) { var $ = jQuery, - HIGHLIGHTED_ROW_CLASS = 'source-line-highlighted', - log = function (message) { - return console.log('Source Viewer:', message); - }; + HIGHLIGHTED_ROW_CLASS = 'source-line-highlighted'; return Marionette.ItemView.extend({ className: 'source', @@ -42,8 +41,10 @@ define([ events: function () { return { + 'click .source-line-scm': 'showSCMPopup', 'click .source-line-covered': 'showCoveragePopup', 'click .source-line-partially-covered': 'showCoveragePopup', + 'click .source-line-uncovered': 'showCoveragePopup', 'click .source-line-duplications': 'showDuplications', 'click .source-line-duplications-extra': 'showDuplicationPopup', 'click .source-line-number[data-line-number]': 'highlightLine' @@ -62,7 +63,6 @@ define([ }, onRender: function () { - log('Render'); this.renderIssues(); }, @@ -83,12 +83,10 @@ define([ this.requestComponent().done(function () { that.requestSource() .done(function () { - that.requestCoverage().done(function () { - that.requestDuplications().done(function () { - that.requestIssues().done(function () { - that.render(); - that.trigger('loaded'); - }); + that.requestDuplications().done(function () { + that.requestIssues().done(function () { + that.render(); + that.trigger('loaded'); }); }); }) @@ -108,7 +106,6 @@ define([ }, requestComponent: function () { - log('Request component details...'); var that = this, url = baseUrl + '/api/components/app', options = { key: this.model.key() }; @@ -124,57 +121,43 @@ define([ }; }, + getCoverageStatus: function (row) { + var status = null; + if (row.lineHits > 0) { + status = 'partially-covered'; + } + if (row.lineHits > 0 && row.conditions === row.coveredConditions) { + status = 'covered'; + } + if (row.lineHits === 0 || row.coveredConditions === 0) { + status = 'uncovered'; + } + return status; + }, + requestSource: function () { - log('Request source...'); var that = this, url = baseUrl + '/api/sources/lines', options = _.extend({ uuid: this.model.id }, this.linesLimit()); return $.get(url, options, function (data) { - var source = data.sources || []; + var source = (data.sources || []).slice(0); if (source.length === 0 || (source.length > 0 && _.first(source).line === 1)) { source.unshift({ line: 0 }); } - var firstLine = _.first(source).line; + source = source.map(function (row) { + return _.extend(row, { coverageStatus: that.getCoverageStatus(row) }); + }); + var firstLine = _.first(source).line, + linesRequested = options.to - options.from + 1; that.model.set({ source: source, hasSourceBefore: firstLine > 1, - hasSourceAfter: true + hasSourceAfter: data.sources.length === linesRequested }); - log('Source loaded'); - }); - }, - - requestCoverage: function () { - log('Request coverage'); - var that = this, - url = baseUrl + '/api/coverage/show', - options = { key: this.model.key() }; - return $.get(url, options, function (data) { - var hasCoverage = (data != null) && (data.coverage != null), - coverage = []; - that.model.set({ hasCoverage: hasCoverage }); - if (hasCoverage) { - coverage = data.coverage.map(function (c) { - var status = 'partially-covered'; - if (c[1] && c[3] === c[4]) { - status = 'covered'; - } - if (!c[1] || c[4] === 0) { - status = 'uncovered'; - } - return { - line: +c[0], - covered: status - }; - }); - } - that.model.addMeta(coverage); - log('Coverage loaded'); }); }, requestDuplications: function () { - log('Request duplications'); var that = this, url = baseUrl + '/api/duplications/show', options = { key: this.model.key() }; @@ -207,12 +190,10 @@ define([ duplications: data.duplications, duplicationFiles: data.files }); - log('Duplications loaded'); }); }, requestIssues: function () { - log('Request issues'); var that = this, options = { data: { @@ -226,7 +207,6 @@ define([ return this.issues.fetch(options).done(function () { that.issues.reset(that.limitIssues(that.issues)); that.addIssuesPerLineMeta(that.issues); - log('Issues loaded'); }); }, @@ -253,9 +233,7 @@ define([ }, renderIssues: function () { - log('Render issues'); this.issues.forEach(this.renderIssue, this); - log('Issues rendered'); }, renderIssue: function (issue) { @@ -279,11 +257,24 @@ define([ this.renderIssue(issue); }, + showSCMPopup: function (e) { + e.stopPropagation(); + $('body').click(); + var line = +$(e.currentTarget).data('line-number'), + row = _.findWhere(this.model.get('source'), { line: line }), + popup = new SCMPopupView({ + triggerEl: $(e.currentTarget), + model: new Backbone.Model(row) + }); + popup.render(); + }, + showCoveragePopup: function (e) { e.stopPropagation(); $('body').click(); var r = window.process.addBackgroundProcess(), line = $(e.currentTarget).data('line-number'), + row = _.findWhere(this.model.get('source'), { line: line }), url = baseUrl + '/api/tests/test_cases', options = { key: this.model.key(), @@ -292,6 +283,7 @@ define([ return $.get(url, options).done(function (data) { var popup = new CoveragePopupView({ model: new Backbone.Model(data), + row: row, triggerEl: $(e.currentTarget) }); popup.render(); @@ -302,8 +294,7 @@ define([ }, showDuplications: function () { - this.$('.source-line-duplications').addClass('hidden'); - this.$('.source-line-duplications-extra').removeClass('hidden'); + this.$el.addClass('source-duplications-expanded'); }, showDuplicationPopup: function (e) { diff --git a/server/sonar-web/src/main/less/components/source.less b/server/sonar-web/src/main/less/components/source.less index 7ef086a2aaa..32d1e8001b0 100644 --- a/server/sonar-web/src/main/less/components/source.less +++ b/server/sonar-web/src/main/less/components/source.less @@ -105,9 +105,27 @@ background-color: @barBackgroundColor; } +.source-line-duplications-extra { + display: none; +} + +.source-duplications-expanded { + .source-line-duplications { + display: none; + } + + .source-line-duplications-extra { + display: table-cell; + } +} + .source-line-scm { padding: 0 5px; background-color: @barBackgroundColor; + + &[data-line-number] { + cursor: pointer; + } } .source-line-scm-inner { @@ -133,6 +151,7 @@ .source-line-uncovered { background-color: @red !important; + cursor: pointer; } .source-line-partially-covered { diff --git a/server/sonar-web/src/main/less/issues.less b/server/sonar-web/src/main/less/issues.less index 17b29cb0e45..2948a304938 100644 --- a/server/sonar-web/src/main/less/issues.less +++ b/server/sonar-web/src/main/less/issues.less @@ -301,8 +301,6 @@ .issues-workspace-list-more { margin-top: 10px; padding: 5px 10px; - border: 1px solid @barBorderColor; - background: @barBackgroundColor; text-align: center; } diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 24fd83f4fb7..c9f03748885 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2765,6 +2765,11 @@ component_viewer.workspace.tooltip=Keeps track of history of navigation component_viewer.workspace.show_workspace=Show workspace component_viewer.workspace.hide_workspace=Hide workspace +source_viewer.covered=Covered +source_viewer.not_covered=Not covered +source_viewer.conditions=conditions +source_viewer.expand_duplications=Click to display more in details all the duplicated blocks of this file + #------------------------------------------------------------------------------ # |