diff options
Diffstat (limited to 'server/sonar-web/src/main/js')
9 files changed, 148 insertions, 15 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/component-viewer/issue-view.js b/server/sonar-web/src/main/js/apps/issues/component-viewer/issue-view.js index 6d8a6f73207..97d3e2b40e9 100644 --- a/server/sonar-web/src/main/js/apps/issues/component-viewer/issue-view.js +++ b/server/sonar-web/src/main/js/apps/issues/component-viewer/issue-view.js @@ -5,7 +5,7 @@ define([ return IssueView.extend({ onRender: function () { IssueView.prototype.onRender.apply(this, arguments); - this.$el.removeClass('issue-navigate-right'); + this.$el.removeClass('issue-navigate-right issue-with-checkbox'); }, serializeData: function () { diff --git a/server/sonar-web/src/main/js/apps/issues/models/issues.js b/server/sonar-web/src/main/js/apps/issues/models/issues.js index af41dd3fe12..2292dba2c8b 100644 --- a/server/sonar-web/src/main/js/apps/issues/models/issues.js +++ b/server/sonar-web/src/main/js/apps/issues/models/issues.js @@ -59,6 +59,16 @@ define([ return this.forEach(function (issue, index) { return issue.set({ index: index }); }); + }, + + selectByKeys: function (keys) { + var that = this; + keys.forEach(function (key) { + var issue = that.get(key); + if (issue) { + issue.set({ selected: true }); + } + }); } }); diff --git a/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-checkbox.hbs b/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-checkbox.hbs new file mode 100644 index 00000000000..dbb50e24779 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-checkbox.hbs @@ -0,0 +1,3 @@ +<div class="js-toggle issue-checkbox-container"> + <i class="issue-checkbox icon-checkbox {{#if selected}}icon-checkbox-checked{{/if}}"></i> +</div> diff --git a/server/sonar-web/src/main/js/apps/issues/templates/issues-workspace-header.hbs b/server/sonar-web/src/main/js/apps/issues/templates/issues-workspace-header.hbs index 2e2c9d2ff78..131af89407d 100644 --- a/server/sonar-web/src/main/js/apps/issues/templates/issues-workspace-header.hbs +++ b/server/sonar-web/src/main/js/apps/issues/templates/issues-workspace-header.hbs @@ -20,7 +20,11 @@ {{/with}} </div> {{else}} - + {{#if state.canBulkChange}} + <a class="js-selection icon-checkbox {{#if allSelected}}icon-checkbox-checked{{/if}} {{#if someSelected}}icon-checkbox-checked icon-checkbox-single{{/if}}"></a> + {{else}} + + {{/if}} {{/if}} </div> @@ -30,7 +34,11 @@ <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> + <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> @@ -39,11 +47,21 @@ {{/notNull}} - <div class="search-navigator-header-buttons button-group"> + <div class="search-navigator-header-buttons button-group dropdown"> <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> + <button id="issues-bulk-change" class="dropdown-toggle" data-toggle="dropdown">{{t "bulk_change"}}</button> + <ul class="dropdown-menu dropdown-menu-right"> + <li> + <a class="js-bulk-change" href="#">{{tp 'issues.bulk_change' state.total}}</a> + </li> + {{#gt selectedCount 0}} + <li> + <a class="js-bulk-change-selected" href="#">{{tp 'issues.bulk_change_selected' selectedCount}}</a> + </li> + {{/gt}} + </ul> {{/if}} </div> </div> diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js index 620b68bfccd..e7b317442b9 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-header-view.js @@ -10,25 +10,73 @@ define([ events: function () { return _.extend(WorkspaceHeaderView.prototype.events.apply(this, arguments), { + 'click .js-selection': 'onSelectionClick', 'click .js-back': 'returnToList', - 'click .js-new-search': 'newSearch' + 'click .js-new-search': 'newSearch', + 'click .js-bulk-change-selected': 'onBulkChangeSelectedClick' }); }, initialize: function () { - var that = this; WorkspaceHeaderView.prototype.initialize.apply(this, arguments); this._onBulkIssues = window.onBulkIssues; - window.onBulkIssues = function () { - $('#modal').dialog('close'); - return that.options.app.controller.fetchList(); - }; + window.onBulkIssues = _.bind(this.afterBulkChange, this); }, onClose: function () { window.onBulkIssues = this._onBulkIssues; }, + onSelectionClick: function (e) { + e.preventDefault(); + this.toggleSelection(); + }, + + onBulkChangeSelectedClick: function (e) { + e.preventDefault(); + this.bulkChangeSelected(); + }, + + afterBulkChange: function () { + var that = this; + $('#modal').dialog('close'); + var selectedIndex = this.options.app.state.get('selectedIndex'); + var selectedKeys = _.pluck(this.options.app.list.where({ selected: true }), 'id'); + this.options.app.controller.fetchList().done(function () { + that.options.app.state.set({ selectedIndex: selectedIndex }); + that.options.app.list.selectByKeys(selectedKeys); + }); + }, + + render: function () { + if (!this._suppressUpdate) { + this._super(); + } + }, + + toggleSelection: function () { + this._suppressUpdate = true; + var selectedCount = this.options.app.list.where({ selected: true }).length, + someSelected = selectedCount > 0; + return someSelected ? this.selectNone() : this.selectAll(); + }, + + selectNone: function () { + this.options.app.list.where({ selected: true }).forEach(function (issue) { + issue.set({ selected: false }); + }); + this._suppressUpdate = false; + this.render(); + }, + + selectAll: function () { + this.options.app.list.forEach(function (issue) { + issue.set({ selected: true }); + }); + this._suppressUpdate = false; + this.render(); + }, + returnToList: function () { this.options.app.controller.closeComponentViewer(); }, @@ -41,6 +89,26 @@ define([ var query = this.options.app.controller.getQuery('&', true), url = baseUrl + '/issues/bulk_change_form?' + query; window.openModalWindow(url, {}); + }, + + bulkChangeSelected: function () { + var selected = this.options.app.list.where({ selected: true }), + selectedKeys = _.first(_.pluck(selected, 'id'), 200), + query = 'issues=' + selectedKeys.join(), + url = baseUrl + '/issues/bulk_change_form?' + query; + window.openModalWindow(url, {}); + }, + + serializeData: function () { + var issuesCount = this.options.app.list.length, + selectedCount = this.options.app.list.where({ selected: true }).length, + allSelected = issuesCount > 0 && issuesCount === selectedCount, + someSelected = !allSelected && selectedCount > 0; + return _.extend(this._super(), { + selectedCount: selectedCount, + allSelected: allSelected, + someSelected: someSelected + }); } }); diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js index 002fafb0709..510f26c63ea 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-list-item-view.js @@ -16,6 +16,7 @@ define([ }; return IssueView.extend({ + checkboxTemplate: Templates['issues-issue-checkbox'], filterTemplate: Templates['issues-issue-filter'], events: function () { @@ -23,7 +24,8 @@ define([ 'click': 'selectCurrent', 'dblclick': 'openComponentViewer', 'click .js-issue-navigate': 'openComponentViewer', - 'click .js-issue-filter': 'onIssueFilterClick' + 'click .js-issue-filter': 'onIssueFilterClick', + 'click .js-toggle': 'onIssueToggle' }); }, @@ -36,7 +38,11 @@ define([ IssueView.prototype.onRender.apply(this, arguments); this.select(); this.addFilterSelect(); + this.addCheckbox(); this.$el.addClass('issue-navigate-right'); + if (this.options.app.state.get('canBulkChange')) { + this.$el.addClass('issue-with-checkbox'); + } }, onIssueFilterClick: function (e) { @@ -67,12 +73,23 @@ define([ this.popup.render(); }, + onIssueToggle: function (e) { + e.preventDefault(); + this.model.set({ selected: !this.model.get('selected') }); + var selected = this.model.collection.where({ selected: true }).length; + this.options.app.state.set({ selected: selected }); + }, + addFilterSelect: function () { this.$('.issue-table-meta-cell-first') .find('.issue-meta-list') .append(this.filterTemplate(this.model.toJSON())); }, + addCheckbox: function () { + this.$el.append(this.checkboxTemplate(this.model.toJSON())); + }, + select: function () { var selected = this.model.get('index') === this.options.app.state.get('selectedIndex'); this.$el.toggleClass('selected', selected); @@ -86,8 +103,14 @@ define([ var that = this; var key = this.model.get('key'), componentUuid = this.model.get('componentUuid'), - index = this.model.get('index'); - this.model.reset({ key: key, componentUuid: componentUuid, index: index }, { silent: true }); + index = this.model.get('index'), + selected = this.model.get('selected'); + this.model.reset({ + key: key, + componentUuid: componentUuid, + index: index, + selected: selected + }, { silent: true }); return this.model.fetch(options).done(function () { return that.trigger('reset'); }); diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js index 37e7ade70e9..d4bdad5f65b 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js @@ -32,6 +32,11 @@ define([ that.options.app.controller.showComponentViewer(selectedIssue); return false; }); + key('space', 'list', function () { + var selectedIssue = that.collection.at(that.options.app.state.get('selectedIndex')); + selectedIssue.set({ selected: !selectedIssue.get('selected') }); + return false; + }); key('f', 'list', function () { return doAction('transition'); }); diff --git a/server/sonar-web/src/main/js/apps/nav/templates/nav-shortcuts-help.hbs b/server/sonar-web/src/main/js/apps/nav/templates/nav-shortcuts-help.hbs index 9457d1b7762..5230e7f5912 100644 --- a/server/sonar-web/src/main/js/apps/nav/templates/nav-shortcuts-help.hbs +++ b/server/sonar-web/src/main/js/apps/nav/templates/nav-shortcuts-help.hbs @@ -40,6 +40,7 @@ </li> <li><span class="shortcut-button">→</span> {{t 'shortcuts.section.issues.open_details'}}</li> <li><span class="shortcut-button">←</span> {{t 'shortcuts.section.issues.return_to_list'}}</li> + <li><span class="shortcut-button">⎵</span> {{t 'shortcuts.section.issue.select'}}</li> <li><span class="shortcut-button">f</span> {{t 'shortcuts.section.issue.do_transition'}}</li> <li><span class="shortcut-button">a</span> {{t 'shortcuts.section.issue.assign'}}</li> <li><span class="shortcut-button">m</span> {{t 'shortcuts.section.issue.assign_to_me'}}</li> diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js index 071d51c69b2..bc4296fcb8a 100644 --- a/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js +++ b/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js @@ -29,7 +29,7 @@ define(function () { events: function () { return { - 'click .js-bulk-change': 'bulkChange', + 'click .js-bulk-change': 'onBulkChangeClick', 'click .js-reload': 'reload', 'click .js-next': 'selectNext', 'click .js-prev': 'selectPrev' @@ -40,6 +40,11 @@ define(function () { this.listenTo(options.app.state, 'change', this.render); }, + onBulkChangeClick: function (e) { + e.preventDefault(); + this.bulkChange(); + }, + bulkChange: function () { }, |