diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2015-07-08 12:02:44 +0200 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-07-08 14:08:00 +0200 |
commit | 7a4939f74f1bc53203eb99945182adeb7ab750da (patch) | |
tree | efddc46d7afbdb9bd59eda48196a7aec571adf03 | |
parent | afa5a589582cfd710a8f83ff410204e082c14dfe (diff) | |
download | sonarqube-7a4939f74f1bc53203eb99945182adeb7ab750da.tar.gz sonarqube-7a4939f74f1bc53203eb99945182adeb7ab750da.zip |
SONAR-6697 add new custom measures page
25 files changed, 564 insertions, 1 deletions
diff --git a/server/sonar-web/Gruntfile.coffee b/server/sonar-web/Gruntfile.coffee index 8e61d0b9553..1e74a5f7812 100644 --- a/server/sonar-web/Gruntfile.coffee +++ b/server/sonar-web/Gruntfile.coffee @@ -120,6 +120,7 @@ module.exports = (grunt) -> 'build-app:api-documentation' 'build-app:coding-rules' 'build-app:computation' + 'build-app:custom-measures' 'build-app:drilldown' 'build-app:groups' 'build-app:issues' @@ -213,10 +214,13 @@ module.exports = (grunt) -> ] '<%= BUILD_PATH %>/js/apps/account/templates.js': [ '<%= SOURCE_PATH %>/js/apps/account/templates/**/*.hbs' - ], + ] '<%= BUILD_PATH %>/js/apps/update-center/templates.js': [ '<%= SOURCE_PATH %>/js/apps/update-center/templates/**/*.hbs' ] + '<%= BUILD_PATH %>/js/apps/custom-measures/templates.js': [ + '<%= SOURCE_PATH %>/js/apps/custom-measures/templates/**/*.hbs' + ] clean: diff --git a/server/sonar-web/src/main/js/apps/custom-measures/app.js b/server/sonar-web/src/main/js/apps/custom-measures/app.js new file mode 100644 index 00000000000..de6316fb658 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/app.js @@ -0,0 +1,53 @@ +define([ + './layout', + './custom-measures', + './header-view', + './list-view', + './list-footer-view' +], function (Layout, CustomMeasures, HeaderView, ListView, ListFooterView) { + + var App = new Marionette.Application(), + init = function (options) { + // Layout + this.layout = new Layout({ + el: options.el + }); + this.layout.render(); + + // Collection + this.customMeasures = new CustomMeasures({ + projectId: options.projectId + }); + + // Header View + this.headerView = new HeaderView({ + collection: this.customMeasures, + projectId: options.projectId + }); + this.layout.headerRegion.show(this.headerView); + + // List View + this.listView = new ListView({ + collection: this.customMeasures + }); + this.layout.listRegion.show(this.listView); + + // List Footer View + this.listFooterView = new ListFooterView({ + collection: this.customMeasures + }); + this.layout.listFooterRegion.show(this.listFooterView); + + // Go! + this.customMeasures.fetch(); + }; + + App.on('start', function (options) { + window.requestMessages().done(function () { + init.call(App, options); + }); + }); + + return App; + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/create-view.js b/server/sonar-web/src/main/js/apps/custom-measures/create-view.js new file mode 100644 index 00000000000..d7461fe7158 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/create-view.js @@ -0,0 +1,32 @@ +define([ + './custom-measure', + './form-view' +], function (CustomMeasure, FormView) { + + return FormView.extend({ + + sendRequest: function () { + var that = this, + customMeasure = new CustomMeasure({ + metricId: this.$('#create-custom-measure-metric').val(), + value: this.$('#create-custom-measure-value').val(), + description: this.$('#create-custom-measure-description').val(), + projectId: this.options.projectId + }); + this.disableForm(); + return customMeasure.save(null, { + statusCode: { + // do not show global error + 400: null + } + }).done(function () { + that.collection.refresh(); + that.destroy(); + }).fail(function (jqXHR) { + that.enableForm(); + that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/custom-measure.js b/server/sonar-web/src/main/js/apps/custom-measures/custom-measure.js new file mode 100644 index 00000000000..fce8bf4fbdf --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/custom-measure.js @@ -0,0 +1,37 @@ +define(function () { + + return Backbone.Model.extend({ + idAttribute: 'id', + + urlRoot: function () { + return baseUrl + '/api/custom_measures'; + }, + + sync: function (method, model, options) { + var opts = options || {}; + if (method === 'create') { + _.defaults(opts, { + url: this.urlRoot() + '/create', + type: 'POST', + data: _.pick(model.toJSON(), 'metricId', 'value', 'description', 'projectId') + }); + } + if (method === 'update') { + _.defaults(opts, { + url: this.urlRoot() + '/update', + type: 'POST', + data: _.pick(model.toJSON(), 'id', 'value', 'description') + }); + } + if (method === 'delete') { + _.defaults(opts, { + url: this.urlRoot() + '/delete', + type: 'POST', + data: { id: this.id } + }); + } + return Backbone.ajax(opts); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/custom-measures.js b/server/sonar-web/src/main/js/apps/custom-measures/custom-measures.js new file mode 100644 index 00000000000..4d2c6d29797 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/custom-measures.js @@ -0,0 +1,45 @@ +define([ + './custom-measure' +], function (CustomMeasure) { + + return Backbone.Collection.extend({ + model: CustomMeasure, + + initialize: function (options) { + this.projectId = options.projectId; + }, + + url: function () { + return baseUrl + '/api/custom_measures/search'; + }, + + parse: function (r) { + this.total = r.total; + this.p = r.p; + this.ps = r.ps; + return r.customMeasures; + }, + + fetch: function (options) { + var opts = _.defaults(options || {}, { data: {} }); + this.q = opts.data.q; + opts.data.projectId = this.projectId; + return this._super(opts); + }, + + fetchMore: function () { + var p = this.p + 1; + return this.fetch({ add: true, remove: false, data: { p: p, ps: this.ps, q: this.q } }); + }, + + refresh: function () { + return this.fetch({ reset: true, data: { q: this.q } }); + }, + + hasMore: function () { + return this.total > this.p * this.ps; + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/delete-view.js b/server/sonar-web/src/main/js/apps/custom-measures/delete-view.js new file mode 100644 index 00000000000..1838b83e044 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/delete-view.js @@ -0,0 +1,32 @@ +define([ + 'components/common/modal-form', + './templates' +], function (ModalForm) { + + return ModalForm.extend({ + template: Templates['custom-measures-delete'], + + onFormSubmit: function (e) { + this._super(e); + this.sendRequest(); + }, + + sendRequest: function () { + var that = this, + collection = this.model.collection; + return this.model.destroy({ + wait: true, + statusCode: { + // do not show global error + 400: null + } + }).done(function () { + collection.refresh(); + that.destroy(); + }).fail(function (jqXHR) { + that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/form-view.js b/server/sonar-web/src/main/js/apps/custom-measures/form-view.js new file mode 100644 index 00000000000..43a62a7de83 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/form-view.js @@ -0,0 +1,41 @@ +define([ + 'components/common/modal-form', + 'apps/metrics/metrics', + './templates' +], function (ModalForm, Metrics) { + + return ModalForm.extend({ + template: Templates['custom-measures-form'], + + initialize: function () { + this.metrics = new Metrics(); + this.listenTo(this.metrics, 'reset', this.render); + this.metrics.fetch({ reset: true }); + }, + + onRender: function () { + this._super(); + this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); + this.$('#create-custom-measure-metric').select2({ + width: '250px', + minimumResultsForSearch: 20 + }); + }, + + onDestroy: function () { + this._super(); + this.$('[data-toggle="tooltip"]').tooltip('destroy'); + }, + + onFormSubmit: function (e) { + this._super(e); + this.sendRequest(); + }, + + serializeData: function () { + // TODO show only not taken metrics + return _.extend(this._super(), { metrics: this.metrics.toJSON() }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/header-view.js b/server/sonar-web/src/main/js/apps/custom-measures/header-view.js new file mode 100644 index 00000000000..8b22efcec5a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/header-view.js @@ -0,0 +1,26 @@ +define([ + './create-view', + './templates' +], function (CreateView) { + + return Marionette.ItemView.extend({ + template: Templates['custom-measures-header'], + + events: { + 'click #custom-measures-create': 'onCreateClick' + }, + + onCreateClick: function (e) { + e.preventDefault(); + this.createCustomMeasure(); + }, + + createCustomMeasure: function () { + new CreateView({ + collection: this.collection, + projectId: this.options.projectId + }).render(); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/layout.js b/server/sonar-web/src/main/js/apps/custom-measures/layout.js new file mode 100644 index 00000000000..b4aa4ece791 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/layout.js @@ -0,0 +1,15 @@ +define([ + './templates' +], function () { + + return Marionette.LayoutView.extend({ + template: Templates['custom-measures-layout'], + + regions: { + headerRegion: '#custom-measures-header', + listRegion: '#custom-measures-list', + listFooterRegion: '#custom-measures-list-footer' + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/list-footer-view.js b/server/sonar-web/src/main/js/apps/custom-measures/list-footer-view.js new file mode 100644 index 00000000000..d66c27ad335 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/list-footer-view.js @@ -0,0 +1,34 @@ +define([ + './templates' +], function () { + + return Marionette.ItemView.extend({ + template: Templates['custom-measures-list-footer'], + + collectionEvents: { + 'all': 'render' + }, + + events: { + 'click #custom-measures-fetch-more': 'onMoreClick' + }, + + onMoreClick: function (e) { + e.preventDefault(); + this.fetchMore(); + }, + + fetchMore: function () { + this.collection.fetchMore(); + }, + + serializeData: function () { + return _.extend(this._super(), { + total: this.collection.total, + count: this.collection.length, + more: this.collection.hasMore() + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/list-item-view.js b/server/sonar-web/src/main/js/apps/custom-measures/list-item-view.js new file mode 100644 index 00000000000..97d9671eb17 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/list-item-view.js @@ -0,0 +1,48 @@ +define([ + './update-view', + './delete-view', + './templates' +], function (UpdateView, DeleteView) { + + return Marionette.ItemView.extend({ + tagName: 'li', + className: 'panel panel-vertical', + template: Templates['custom-measures-list-item'], + + events: { + 'click .js-custom-measure-update': 'onUpdateClick', + 'click .js-custom-measure-delete': 'onDeleteClick' + }, + + onRender: function () { + this.$el.attr('data-id', this.model.id); + this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); + }, + + onDestroy: function () { + this.$('[data-toggle="tooltip"]').tooltip('destroy'); + }, + + onUpdateClick: function (e) { + e.preventDefault(); + this.updateCustomMeasure(); + }, + + onDeleteClick: function (e) { + e.preventDefault(); + this.deleteCustomMeasure(); + }, + + updateCustomMeasure: function () { + new UpdateView({ + model: this.model, + collection: this.model.collection + }).render(); + }, + + deleteCustomMeasure: function () { + new DeleteView({ model: this.model }).render(); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/list-view.js b/server/sonar-web/src/main/js/apps/custom-measures/list-view.js new file mode 100644 index 00000000000..24878864d30 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/list-view.js @@ -0,0 +1,11 @@ +define([ + './list-item-view', + './templates' +], function (ListItemView) { + + return Marionette.CollectionView.extend({ + tagName: 'ul', + childView: ListItemView + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-delete.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-delete.hbs new file mode 100644 index 00000000000..87a29038ba1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-delete.hbs @@ -0,0 +1,13 @@ +<form id="delete-custom-measure-form"> + <div class="modal-head"> + <h2>Delete Custom Measure</h2> + </div> + <div class="modal-body"> + <div class="js-modal-messages"></div> + Are you sure you want to delete custom measure "{{metric.name}}"? + </div> + <div class="modal-foot"> + <button id="delete-custom-measure-submit" class="button-red">Delete</button> + <a href="#" class="js-modal-close" id="delete-custom-measure-cancel">Cancel</a> + </div> +</form> diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-form.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-form.hbs new file mode 100644 index 00000000000..52e16a0e98b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-form.hbs @@ -0,0 +1,30 @@ +<form id="create-custom-measure-form" autocomplete="off"> + <div class="modal-head"> + <h2>{{#if id}}Update{{else}}Create{{/if}} Custom Measure</h2> + </div> + <div class="modal-body"> + <div class="js-modal-messages"></div> + {{#unless id}} + <div class="modal-field"> + <label for="create-custom-measure-metric">Metric<em class="mandatory">*</em></label> + <select id="create-custom-measure-metric" name="metric" required> + {{#each metrics}} + <option value="{{id}}" {{#eq id ../metric.id}}selected{{/eq}}>{{name}}</option> + {{/each}} + </select> + </div> + {{/unless}} + <div class="modal-field"> + <label for="create-custom-measure-value">Value<em class="mandatory">*</em></label> + <input id="create-custom-measure-value" name="value" type="text" maxlength="200" required value="{{value}}"> + </div> + <div class="modal-field"> + <label for="create-custom-measure-description">Description</label> + <textarea id="create-custom-measure-description" name="description">{{description}}</textarea> + </div> + </div> + <div class="modal-foot"> + <button id="create-custom-measure-submit">{{#if id}}Update{{else}}Create{{/if}}</button> + <a href="#" class="js-modal-close" id="create-custom-measure-cancel">Cancel</a> + </div> +</form> diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-header.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-header.hbs new file mode 100644 index 00000000000..a8183635b8c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-header.hbs @@ -0,0 +1,9 @@ +<header class="page-header"> + <h1 class="page-title">{{t 'custom_measures.page'}}</h1> + <div class="page-actions"> + <div class="button-group"> + <button id="custom-measures-create">{{t 'create'}}</button> + </div> + </div> + <p class="page-description">{{t 'custom_measures.page.description'}}</p> +</header> diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-layout.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-layout.hbs new file mode 100644 index 00000000000..a7bd51772ff --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-layout.hbs @@ -0,0 +1,5 @@ +<div class="page"> + <div id="custom-measures-header"></div> + <div id="custom-measures-list"></div> + <div id="custom-measures-list-footer"></div> +</div> diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list-footer.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list-footer.hbs new file mode 100644 index 00000000000..3a91e24482c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list-footer.hbs @@ -0,0 +1,6 @@ +<footer class="spacer-top note text-center"> + {{count}}/{{total}} shown + {{#if more}} + <a id="custom-measures-fetch-more" class="spacer-left" href="#">show more</a> + {{/if}} +</footer> diff --git a/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list-item.hbs b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list-item.hbs new file mode 100644 index 00000000000..d8aeedf60d3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/templates/custom-measures-list-item.hbs @@ -0,0 +1,34 @@ +<div class="pull-right big-spacer-left nowrap"> + <a class="js-custom-measure-update icon-edit" title="Update" data-toggle="tooltip" href="#"></a> + <a class="js-custom-measure-delete icon-delete" title="Delete" data-toggle="tooltip" href="#"></a> +</div> + +<div class="display-inline-block text-middle text-right width-10 big-spacer-right text-ellipsis" + title="{{formatMeasure value metric.type}}"> + <span class="js-custom-measure-value emphasised-measure"> + {{formatMeasure value metric.type}} + </span> +</div> + +<div class="display-inline-block text-middle width-20"> + <div> + <strong class="js-custom-measure-metric-name"> + {{metric.name}} + </strong> + {{#if pending}} + <span class="js-custom-measure-pending badge badge-warning spacer-left" + title="{{t 'custom_measures.pending_tooltip'}}" + data-toggle="tooltip" data-placement="bottom">{{t 'custom_measures.pending'}}</span> + {{/if}} + </div> + <span class="js-custom-measure-domain note">{{metric.domain}}</span> +</div> + +<div class="display-inline-block text-top width-20"> + <span class="js-custom-measure-description">{{description}}</span> +</div> + +<div class="display-inline-block text-top width-30"> + Created on <span class="js-custom-measure-created-at">{{d createdAt}}</span> + by <span class="js-custom-measure-user">{{user.name}}</span> +</div> diff --git a/server/sonar-web/src/main/js/apps/custom-measures/update-view.js b/server/sonar-web/src/main/js/apps/custom-measures/update-view.js new file mode 100644 index 00000000000..301c083e5e6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/custom-measures/update-view.js @@ -0,0 +1,29 @@ +define([ + './form-view' +], function (FormView) { + + return FormView.extend({ + + sendRequest: function () { + var that = this; + this.model.set({ + value: this.$('#create-custom-measure-value').val(), + description: this.$('#create-custom-measure-description').val() + }); + this.disableForm(); + return this.model.save(null, { + statusCode: { + // do not show global error + 400: null + } + }).done(function () { + that.collection.refresh(); + that.destroy(); + }).fail(function (jqXHR) { + that.enableForm(); + that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/apps/nav/templates/nav-context-navbar.hbs b/server/sonar-web/src/main/js/apps/nav/templates/nav-context-navbar.hbs index 11ef4f53ad7..189faf5bd7c 100644 --- a/server/sonar-web/src/main/js/apps/nav/templates/nav-context-navbar.hbs +++ b/server/sonar-web/src/main/js/apps/nav/templates/nav-context-navbar.hbs @@ -52,6 +52,9 @@ <li> <a href="{{link '/manual_measures/index?id=' contextKeyEncoded}}">{{t 'manual_measures.page'}}</a> </li> + <li> + <a href="{{link '/custom_measures/index?id=' contextKeyEncoded}}">Custom Measures <span class="badge big-spacer-left">New</span></a> + </li> {{/if}} {{#if component.configuration.showActionPlans}} <li> diff --git a/server/sonar-web/src/main/js/libs/application.js b/server/sonar-web/src/main/js/libs/application.js index fa006f7bacc..e26addbfd1b 100644 --- a/server/sonar-web/src/main/js/libs/application.js +++ b/server/sonar-web/src/main/js/libs/application.js @@ -495,6 +495,7 @@ function closeModalWindow () { * @param {number} value */ var ratingFormatter = function (value) { + value = parseInt(value, 10) return String.fromCharCode(97 + value - 1).toUpperCase(); }; diff --git a/server/sonar-web/src/main/less/init/type.less b/server/sonar-web/src/main/less/init/type.less index 490dd34e895..dd16c4d3f83 100644 --- a/server/sonar-web/src/main/less/init/type.less +++ b/server/sonar-web/src/main/less/init/type.less @@ -65,6 +65,11 @@ sub { vertical-align: text-bottom; } em { font-style: italic; } strong { font-weight: 500; } +.emphasised-measure { + font-size: 24px; + font-weight: 300; +} + // Quotes diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/custom_measures_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/custom_measures_controller.rb new file mode 100644 index 00000000000..d811f1ddc56 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/custom_measures_controller.rb @@ -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. +# +class CustomMeasuresController < ApplicationController + + SECTION=Navigation::SECTION_RESOURCE + before_filter :init_resource_for_admin_role + + def index + + end + +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb new file mode 100644 index 00000000000..54ba4fcdac4 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/custom_measures/index.html.erb @@ -0,0 +1,7 @@ +<% content_for :extra_script do %> + <script> + require(['apps/custom-measures/app'], function (App) { + App.start({ el: '#content', projectId: '<%= @resource.uuid -%>' }); + }); + </script> +<% end %> 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 4a98a79471e..fd9b4b79784 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -466,6 +466,8 @@ manual_metrics.delete_manual_metric=Delete Manual Metric manual_metrics.delete_manual_metric_message=Are you sure that you want to delete manual metric "{0}"? \n Warning: all the associated manual measures will be deleted. manual_measures.page=Manual Measures manual_measures.page.description=Update the values of manual metrics for this project. Changes will take effect at the project's next analysis. Manual Metrics must be created at the global level. +custom_measures.page=Custom Measures +custom_measures.page.description=Update the values of custom metrics for this project. Changes will take effect at the project's next analysis. Custom metrics must be created at the global level. manual_rules.page=Manual Rules manual_rules.page.description=These rules are available for all projects. Manual issues can be created at project level via the component code viewer. manual_rules.delete_manual_rule=Delete Manual Rule @@ -1580,6 +1582,18 @@ manual_measures.pending_message=Pending measures are marked with orange box. The manual_measures.no_more_available_metric=All available manual metrics have a measure. manual_measures.to_define_new_manual_metric_il_require=You can define new manual metrics if required. + +#------------------------------------------------------------------------------ +# +# CUSTOM MEASURES +# +#------------------------------------------------------------------------------ + +custom_measures.pending=Pending +custom_measures.pending_tooltip=The value will be integrated to project during next analysis. + + + #------------------------------------------------------------------------------ # # MANUAL MEASURES |