From bb004b10dbe983c8042713de7ffb91429419f6ab Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Tue, 14 Apr 2015 14:09:47 +0200 Subject: [PATCH] SONAR-5851 add changelog --- .../quality-profile-changelog.hbs | 48 +++++++++++++ .../quality-profiles-profile-details.hbs | 7 +- .../main/js/common/handlebars-extensions.js | 9 +++ .../src/main/js/quality-profiles/helpers.js | 14 ++++ .../profile-changelog-view.js | 43 +++++++++++ .../quality-profiles/profile-details-view.js | 70 ++++++++++-------- .../src/main/js/quality-profiles/profile.js | 20 ++++++ .../sonar-web/src/test/js/quality-profiles.js | 72 +++++++++++++++++++ .../test/json/quality-profiles/changelog.json | 28 ++++++++ .../json/quality-profiles/changelog2.json | 13 ++++ .../resources/org/sonar/l10n/core.properties | 12 ++-- 11 files changed, 294 insertions(+), 42 deletions(-) create mode 100644 server/sonar-web/src/main/hbs/quality-profiles/quality-profile-changelog.hbs create mode 100644 server/sonar-web/src/main/js/quality-profiles/profile-changelog-view.js create mode 100644 server/sonar-web/src/test/json/quality-profiles/changelog.json create mode 100644 server/sonar-web/src/test/json/quality-profiles/changelog2.json diff --git a/server/sonar-web/src/main/hbs/quality-profiles/quality-profile-changelog.hbs b/server/sonar-web/src/main/hbs/quality-profiles/quality-profile-changelog.hbs new file mode 100644 index 00000000000..d9b184cdb6d --- /dev/null +++ b/server/sonar-web/src/main/hbs/quality-profiles/quality-profile-changelog.hbs @@ -0,0 +1,48 @@ + + +{{#notEmpty events}} + + + + + + + + + + + + {{#each events}} + + + + + + + + {{/each}} + +
{{t 'date'}}{{t 'user'}}{{t 'action'}}{{t 'rule'}}{{t 'parameters'}}
{{dt date}}{{default authorName 'System'}}{{t 'quality_profiles.changelog' action}}{{ruleName}} +
    + {{#each params}} +
  • + {{#eq @key 'severity'}} + {{severityChangelog this}} + {{else}} + {{parameterChangelog @key this}} + {{/eq}} +
  • + {{/each}} +
+
+ + {{#unlessLength events totalEvents}} +

+ {{t 'show_more'}} +

+ {{/unlessLength}} +{{/notEmpty}} diff --git a/server/sonar-web/src/main/hbs/quality-profiles/quality-profiles-profile-details.hbs b/server/sonar-web/src/main/hbs/quality-profiles/quality-profiles-profile-details.hbs index 2dbd17a71ca..502448d9f7a 100644 --- a/server/sonar-web/src/main/hbs/quality-profiles/quality-profiles-profile-details.hbs +++ b/server/sonar-web/src/main/hbs/quality-profiles/quality-profiles-profile-details.hbs @@ -108,9 +108,4 @@ -
- -

Coming soon...

-
+
diff --git a/server/sonar-web/src/main/js/common/handlebars-extensions.js b/server/sonar-web/src/main/js/common/handlebars-extensions.js index c449d0278cc..42d3b0085d8 100644 --- a/server/sonar-web/src/main/js/common/handlebars-extensions.js +++ b/server/sonar-web/src/main/js/common/handlebars-extensions.js @@ -30,6 +30,10 @@ return baseUrl + url; }); + Handlebars.registerHelper('rulePermalink', function (ruleKey) { + return baseUrl + '/coding_rules#rule_key=' + encodeURIComponent(ruleKey); + }); + Handlebars.registerHelper('isActiveLink', function () { var args = Array.prototype.slice.call(arguments, 0, -1), options = arguments[arguments.length - 1], @@ -236,6 +240,11 @@ return cond ? options.fn(this) : options.inverse(this); }); + Handlebars.registerHelper('unlessLength', function (array, len, options) { + var cond = _.isArray(array) && array.length === +len; + return cond ? options.inverse(this) : options.fn(this); + }); + Handlebars.registerHelper('eachReverse', function (array, options) { var ret = ''; diff --git a/server/sonar-web/src/main/js/quality-profiles/helpers.js b/server/sonar-web/src/main/js/quality-profiles/helpers.js index e1d3cb57e84..fa3858e126c 100644 --- a/server/sonar-web/src/main/js/quality-profiles/helpers.js +++ b/server/sonar-web/src/main/js/quality-profiles/helpers.js @@ -23,4 +23,18 @@ return baseUrl + '/quality_profiles/show?key=' + encodeURIComponent(key); }); + Handlebars.registerHelper('severityChangelog', function (severity) { + var label = ' ' + t('severity', severity), + message = tp('quality_profiles.severity_set_to_x', label); + return new Handlebars.SafeString(message); + }); + + Handlebars.registerHelper('parameterChangelog', function (value, parameter) { + if (parameter) { + return new Handlebars.SafeString(tp('quality_profiles.parameter_set_to_x', value, parameter)); + } else { + return new Handlebars.SafeString(tp('quality_profiles.changelog.parameter_reset_to_default_value_x', parameter)); + } + }); + })(); diff --git a/server/sonar-web/src/main/js/quality-profiles/profile-changelog-view.js b/server/sonar-web/src/main/js/quality-profiles/profile-changelog-view.js new file mode 100644 index 00000000000..b87406132cd --- /dev/null +++ b/server/sonar-web/src/main/js/quality-profiles/profile-changelog-view.js @@ -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([ + 'templates/quality-profiles' +], function () { + + return Marionette.ItemView.extend({ + template: Templates['quality-profile-changelog'], + + events: { + 'click .js-show-changelog': 'onShowChangelogClick', + 'click .js-show-more-changelog': 'onShowMoreChangelogClick' + }, + + onShowChangelogClick: function (e) { + e.preventDefault(); + this.model.fetchChangelog(); + }, + + onShowMoreChangelogClick: function (e) { + e.preventDefault(); + this.model.fetchChangelog({ next: true }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/quality-profiles/profile-details-view.js b/server/sonar-web/src/main/js/quality-profiles/profile-details-view.js index 8a3ab3fcc51..8c26922ad85 100644 --- a/server/sonar-web/src/main/js/quality-profiles/profile-details-view.js +++ b/server/sonar-web/src/main/js/quality-profiles/profile-details-view.js @@ -19,16 +19,21 @@ */ define([ 'quality-profiles/change-profile-parent-view', + 'quality-profiles/profile-changelog-view', 'common/select-list', 'quality-profiles/helpers', 'templates/quality-profiles' -], function (ChangeProfileParentView) { +], function (ChangeProfileParentView, ProfileChangelogView) { var $ = jQuery; - return Marionette.ItemView.extend({ + return Marionette.Layout.extend({ template: Templates['quality-profiles-profile-details'], + regions: { + changelogRegion: '#quality-profile-changelog' + }, + modelEvents: { 'change': 'render' }, @@ -39,36 +44,41 @@ define([ }, onRender: function () { - var key = this.model.get('key'); if (!this.model.get('isDefault')) { - new SelectList({ - el: this.$('#quality-profile-projects-list'), - width: '100%', - readOnly: false, - focusSearch: false, - format: function (item) { - return item.name; - }, - searchUrl: baseUrl + '/api/qualityprofiles/projects?key=' + encodeURIComponent(key), - selectUrl: baseUrl + '/api/qualityprofiles/add_project', - deselectUrl: baseUrl + '/api/qualityprofiles/remove_project', - extra: { - profileKey: key - }, - selectParameter: 'projectUuid', - selectParameterValue: 'uuid', - 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') - } - }); + this.initProjectsSelect(); } + this.changelogRegion.show(new ProfileChangelogView({ model: this.model })); + }, + + initProjectsSelect: function () { + var key = this.model.get('key'); + new window.SelectList({ + el: this.$('#quality-profile-projects-list'), + width: '100%', + readOnly: false, + focusSearch: false, + format: function (item) { + return item.name; + }, + searchUrl: baseUrl + '/api/qualityprofiles/projects?key=' + encodeURIComponent(key), + selectUrl: baseUrl + '/api/qualityprofiles/add_project', + deselectUrl: baseUrl + '/api/qualityprofiles/remove_project', + extra: { + profileKey: key + }, + selectParameter: 'projectUuid', + selectParameterValue: 'uuid', + 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') + } + }); }, onProfileClick: function (e) { diff --git a/server/sonar-web/src/main/js/quality-profiles/profile.js b/server/sonar-web/src/main/js/quality-profiles/profile.js index c88f747cf97..31339ec98db 100644 --- a/server/sonar-web/src/main/js/quality-profiles/profile.js +++ b/server/sonar-web/src/main/js/quality-profiles/profile.js @@ -72,6 +72,26 @@ define(function () { children: r.children }); }); + }, + + fetchChangelog: function (options) { + var that = this, + url = baseUrl + '/api/qualityprofiles/changelog', + opts = { ps: 100, profileKey: this.id }; + options = _.defaults(options || {}, { next: false }); + if (options.next) { + var page = this.get('eventsPage') || 0; + _.extend(opts, { p: page + 1 }); + } + return $.get(url, opts).done(function (r) { + var events = options.next ? that.get('events') : []; + events = events.concat(r.events); + that.set({ + events: events, + eventsPage: r.p, + totalEvents: r.total + }); + }); } }); diff --git a/server/sonar-web/src/test/js/quality-profiles.js b/server/sonar-web/src/test/js/quality-profiles.js index e8868fd340e..40d48e3a9ea 100644 --- a/server/sonar-web/src/test/js/quality-profiles.js +++ b/server/sonar-web/src/test/js/quality-profiles.js @@ -644,3 +644,75 @@ casper.test.begin(testName('Permalink'), 9, function (test) { test.done(); }); }); + + +casper.test.begin(testName('Changelog'), 22, function (test) { + casper + .start(lib.buildUrl('profiles#show?key=java-sonar-way-67887'), function () { + lib.setDefaultViewport(); + + lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json'); + lib.mockRequestFromFile('/api/rules/search', 'rules.json'); + lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json'); + lib.mockRequestFromFile('/api/qualityprofiles/changelog', 'changelog2.json', { data: { p: '2' } }); + lib.mockRequestFromFile('/api/qualityprofiles/changelog', 'changelog.json'); + }) + + .then(function () { + casper.evaluate(function () { + require(['/js/quality-profiles/app.js']); + }); + }) + + .then(function () { + casper.waitForSelector('.js-show-changelog'); + }) + + .then(function () { + test.assertDoesntExist('.js-show-more-changelog'); + + casper.click('.js-show-changelog'); + casper.waitForSelector('#quality-profile-changelog table'); + }) + + .then(function () { + test.assertDoesntExist('.js-show-changelog'); + test.assertExists('.js-show-more-changelog'); + test.assertElementCount('#quality-profile-changelog tbody tr', 2); + + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(1)', 'April 13 2015 1:44 PM'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(1)', 'System'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(1)', 'ACTIVATED'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(1)', 'Synchronisation should not'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(1)', 'BLOCKER'); + + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', 'April 13 2015 1:44 PM'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', 'Anakin Skywalker'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', 'ACTIVATED'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', 'Double.longBitsToDouble'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', 'threshold'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', '3'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(2)', 'emptyParameter'); + + casper.click('.js-show-more-changelog'); + lib.waitForElementCount('#quality-profile-changelog tbody tr', 3); + }) + + .then(function () { + test.assertDoesntExist('.js-show-changelog'); + test.assertDoesntExist('.js-show-more-changelog'); + + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(3)', 'April 13 2015 1:44 PM'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(3)', 'System'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(3)', 'DEACTIVATED'); + test.assertSelectorContains('#quality-profile-changelog tbody tr:nth-child(3)', 'runFinalizersOnExit'); + }) + + .then(function () { + lib.sendCoverage(); + }) + + .run(function () { + test.done(); + }); +}); diff --git a/server/sonar-web/src/test/json/quality-profiles/changelog.json b/server/sonar-web/src/test/json/quality-profiles/changelog.json new file mode 100644 index 00000000000..196f81cdb36 --- /dev/null +++ b/server/sonar-web/src/test/json/quality-profiles/changelog.json @@ -0,0 +1,28 @@ +{ + "total": 3, + "p": 1, + "ps": 2, + "events": [ + { + "date": "2015-04-13T13:44:23+0200", + "action": "ACTIVATED", + "ruleKey": "squid:S1860", + "ruleName": "Synchronisation should not be based on Strings or boxed primitives", + "params": { + "severity": "BLOCKER" + } + }, + { + "date": "2015-04-13T13:44:23+0200", + "action": "ACTIVATED", + "authorLogin" : "anakin.skywalker", + "authorName" : "Anakin Skywalker", + "ruleKey": "squid:S2127", + "ruleName": "\"Double.longBitsToDouble\" should not be used for \"int\"", + "params": { + "threshold": "3", + "emptyParameter": "" + } + } + ] +} diff --git a/server/sonar-web/src/test/json/quality-profiles/changelog2.json b/server/sonar-web/src/test/json/quality-profiles/changelog2.json new file mode 100644 index 00000000000..d64d6aeaf30 --- /dev/null +++ b/server/sonar-web/src/test/json/quality-profiles/changelog2.json @@ -0,0 +1,13 @@ +{ + "total": 3, + "p": 2, + "ps": 2, + "events": [ + { + "date": "2015-04-13T13:44:23+0200", + "action": "DEACTIVATED", + "ruleKey": "squid:S2151", + "ruleName": "\"runFinalizersOnExit\" should not be called" + } + ] +} 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 bd28ae542db..b1eb6e9d794 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1749,7 +1749,7 @@ quality_profiles.no_version=no version quality_profiles.last_version_x_with_date=last version {0} ({1}) quality_profiles.version_x_with_date=version {0} ({1}) quality_profiles.version_x=version {0} -quality_profiles.parameter_set_to_x=Parameter {0} set to {1} +quality_profiles.parameter_set_to_x=Parameter {0} set to {1} quality_profiles.only_in_profile_x=Only in {0} quality_profiles.with_different_configuration=With different configuration quality_profiles.with_same_configuration=With same configuration @@ -1778,13 +1778,13 @@ quality_profiles.manage_rules_tooltip=Manage rules of this profile quality_profiles.manage_rules_tooltip_x_profile=Manage rules of profile '{0}' quality_profiles.see_rules_tooltip=See rules of this profile quality_profiles.see_rules_tooltip_x_profile=See rules of profile '{0}' -quality_profiles.severity_set_to_x=Severity set to {0}{1} +quality_profiles.severity_set_to_x=Severity set to {0} quality_profiles.changelog_from=Changelog from quality_profiles.changelog.empty=No changes have been done. -quality_profiles.changelog.activated=Activated -quality_profiles.changelog.deactivated=Deactivated -quality_profiles.changelog.updated=Updated -quality_profiles.changelog.parameter_reset_to_default_value_x=Parameter {0} reset to default value +quality_profiles.changelog.ACTIVATED=Activated +quality_profiles.changelog.DEACTIVATED=Deactivated +quality_profiles.changelog.UPDATED=Updated +quality_profiles.changelog.parameter_reset_to_default_value_x=Parameter {0} reset to default value quality_profiles.deleted_profile=The profile {0} doesn't exists anymore quality_profiles.projects_for_default=Every project not specifically associated to a quality profile will be associated to this one by default. quality_profiles.projects_for_default.edit=You must not select specific projects for the default quality profile. -- 2.39.5