diff options
Diffstat (limited to 'sonar-server/src/main/coffee/coding-rules')
20 files changed, 1547 insertions, 0 deletions
diff --git a/sonar-server/src/main/coffee/coding-rules/app.coffee b/sonar-server/src/main/coffee/coding-rules/app.coffee new file mode 100644 index 00000000000..b5029b0f577 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/app.coffee @@ -0,0 +1,343 @@ +requirejs.config + baseUrl: "#{baseUrl}/js" + + paths: + 'backbone': 'third-party/backbone' + 'backbone.marionette': 'third-party/backbone.marionette' + 'handlebars': 'third-party/handlebars' + 'jquery.mockjax': 'third-party/jquery.mockjax' + + shim: + 'backbone.marionette': + deps: ['backbone'] + exports: 'Marionette' + 'backbone': + exports: 'Backbone' + 'handlebars': + exports: 'Handlebars' + + +requirejs [ + 'backbone', 'backbone.marionette', + + 'coding-rules/layout', + 'coding-rules/router', + + # views + 'coding-rules/views/header-view', + 'coding-rules/views/actions-view', + 'coding-rules/views/filter-bar-view', + 'coding-rules/views/coding-rules-list-view', + 'coding-rules/views/coding-rules-bulk-change-view', + 'coding-rules/views/coding-rules-quality-profile-activation-view', + 'coding-rules/views/coding-rules-bulk-change-dropdown-view' + + # filters + 'navigator/filters/base-filters', + 'navigator/filters/choice-filters', + 'navigator/filters/string-filters', + 'navigator/filters/date-filter-view', + 'coding-rules/views/filters/quality-profile-filter-view', + 'coding-rules/views/filters/inheritance-filter-view', + 'coding-rules/views/filters/activation-filter-view', + 'coding-rules/views/filters/characteristic-filter-view', + + 'coding-rules/mockjax', + 'common/handlebars-extensions' +], ( + Backbone, Marionette, + + CodingRulesLayout, + CodingRulesRouter, + + # views + CodingRulesHeaderView, + CodingRulesActionsView, + CodingRulesFilterBarView, + CodingRulesListView, + CodingRulesBulkChangeView, + CodingRulesQualityProfileActivationView, + CodingRulesBulkChangeDropdownView + + # filters + BaseFilters, + ChoiceFilters, + StringFilterView, + DateFilterView, + QualityProfileFilterView, + InheritanceFilterView + ActivationFilterView + CharacteristicFilterView +) -> + + # Create a generic error handler for ajax requests + jQuery.ajaxSetup + error: (jqXHR) -> + text = jqXHR.responseText + errorBox = jQuery('.modal-error') + if jqXHR.responseJSON?.errors? + text = _.pluck(jqXHR.responseJSON.errors, 'msg').join '. ' + if errorBox.length > 0 + errorBox.show().text text + else + alert text + + + # Add html class to mark the page as navigator page + jQuery('html').addClass('navigator-page coding-rules-page'); + + + # Create an Application + App = new Marionette.Application + + + App.getQuery = -> + @filterBarView.getQuery() + + + App.restoreSorting = -> + + + + App.storeQuery = (query, sorting) -> + if sorting + _.extend query, + sort: sorting.sort + asc: '' + sorting.asc + queryString = _.map query, (v, k) -> "#{k}=#{encodeURIComponent(v)}" + @router.navigate queryString.join('|'), replace: true + + + + App.fetchList = (firstPage) -> + query = @getQuery() + fetchQuery = _.extend { pageIndex: @pageIndex }, query + + if @codingRules.sorting + _.extend fetchQuery, + sort: @codingRules.sorting.sort, + asc: @codingRules.sorting.asc + + @storeQuery query, @codingRules.sorting + + @layout.showSpinner 'resultsRegion' + jQuery.ajax + url: "#{baseUrl}/api/codingrules/search" + data: fetchQuery + .done (r) => + if firstPage + @codingRules.reset r.codingrules + else + @codingRules.add r.codingrules + @codingRules.paging = r.paging + @codingRulesListView = new CodingRulesListView + app: @ + collection: @codingRules + @layout.resultsRegion.show @codingRulesListView + @codingRulesListView.selectFirst() + + + + App.fetchFirstPage = -> + @pageIndex = 1 + App.fetchList true + + + App.fetchNextPage = -> + if @pageIndex < @codingRules.paging.pages + @pageIndex++ + App.fetchList false + + + App.getQualityProfile = -> + value = @qualityProfileFilter.get('value') + if value? && value.length == 1 then value[0] else null + + + # Construct layout + App.addInitializer -> + @layout = new CodingRulesLayout app: @ + jQuery('body').append @layout.render().el + + + # Construct header + App.addInitializer -> + @codingRulesHeaderView = new CodingRulesHeaderView app: @ + @layout.headerRegion.show @codingRulesHeaderView + + + # Define coding rules + App.addInitializer -> + @codingRules = new Backbone.Collection + @codingRules.sorting = sort: 'CREATION_DATE', asc: false + + + # Construct status bar + App.addInitializer -> + @codingRulesActionsView = new CodingRulesActionsView + app: @ + collection: @codingRules + @layout.actionsRegion.show @codingRulesActionsView + + + # Construct bulk change views + App.addInitializer -> + @codingRulesBulkChangeView = new CodingRulesBulkChangeView app: @ + @codingRulesBulkChangeDropdownView = new CodingRulesBulkChangeDropdownView app: @ + + + # Construct quality profile activation view + App.addInitializer -> + @codingRulesQualityProfileActivationView = new CodingRulesQualityProfileActivationView app: @ + + + # Define filters + App.addInitializer -> + @filters = new BaseFilters.Filters + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.name' + property: 'name' + type: StringFilterView + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.language' + property: 'languages' + type: ChoiceFilters.ChoiceFilterView + choices: @languages + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.severity' + property: 'severities' + type: ChoiceFilters.ChoiceFilterView + choices: + 'BLOCKER': t 'severity.BLOCKER' + 'CRITICAL': t 'severity.CRITICAL' + 'MAJOR': t 'severity.MAJOR' + 'MINOR': t 'severity.MINOR' + 'INFO': t 'severity.INFO' + choiceIcons: + 'BLOCKER': 'severity-blocker' + 'CRITICAL': 'severity-critical' + 'MAJOR': 'severity-major' + 'MINOR': 'severity-minor' + 'INFO': 'severity-info' + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.tag' + property: 'tags' + type: ChoiceFilters.ChoiceFilterView + choices: @tags + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.characteristic' + property: 'characteristic' + type: CharacteristicFilterView + choices: @characteristics + multiple: false + + @qualityProfileFilter = new BaseFilters.Filter + name: t 'coding_rules.filters.quality_profile' + property: 'quality_profile' + type: QualityProfileFilterView + multiple: false + @filters.add @qualityProfileFilter + + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.activation' + property: 'activation' + type: ActivationFilterView + enabled: false + optional: false + multiple: false + qualityProfileFilter: @qualityProfileFilter + choices: + 'active': t 'coding_rules.filters.activation.active' + 'inactive': t 'coding_rules.filters.activation.inactive' + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.availableSince' + property: 'availableSince' + type: DateFilterView + enabled: false + optional: true + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.description' + property: 'description' + type: StringFilterView + enabled: false + optional: true + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.inheritance' + property: 'inheritance' + type: InheritanceFilterView + enabled: false + optional: true + multiple: false + qualityProfileFilter: @qualityProfileFilter + choices: + 'not_inhertited': t 'coding_rules.filters.inheritance.not_inherited' + 'inhertited': t 'coding_rules.filters.inheritance.inherited' + 'overriden': t 'coding_rules.filters.inheritance.overriden' + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.key' + property: 'key' + type: StringFilterView + enabled: false + optional: true + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.repository' + property: 'repositories' + type: ChoiceFilters.ChoiceFilterView + enabled: false + optional: true + choices: @repositories + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.status' + property: 'statuses' + type: ChoiceFilters.ChoiceFilterView + enabled: false + optional: true + choices: @statuses + + + @filterBarView = new CodingRulesFilterBarView + app: @ + collection: @filters, + extra: sort: '', asc: false + @layout.filtersRegion.show @filterBarView + + + # Start router + App.addInitializer -> + @router = new CodingRulesRouter app: @ + Backbone.history.start() + + + # Call app before start the application + appXHR = jQuery.ajax + url: "#{baseUrl}/api/codingrules/app" + + jQuery.when(appXHR) + .done (r) -> + App.appState = new Backbone.Model + App.state = new Backbone.Model + App.qualityProfiles = r.qualityprofiles + App.languages = r.languages + App.repositories = r.repositories + App.statuses = r.statuses + App.tags = r.tags + App.characteristics = r.characteristics + window.messages = r.messages + + # Remove the initial spinner + jQuery('#coding-rules-page-loader').remove() + + # Start the application + App.start()
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/coding-rules/layout.coffee b/sonar-server/src/main/coffee/coding-rules/layout.coffee new file mode 100644 index 00000000000..dbe8633a152 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/layout.coffee @@ -0,0 +1,29 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class AppLayout extends Marionette.Layout + className: 'navigator coding-rules-navigator' + template: Templates['coding-rules-layout'] + spinner: '<i class="spinner"></i>' + + + regions: + headerRegion: '.navigator-header' + actionsRegion: '.navigator-actions' + resultsRegion: '.navigator-results' + detailsRegion: '.navigator-details' + filtersRegion: '.navigator-filters' + + + onRender: -> + # Adjust details region height + @$(@detailsRegion.el).css 'bottom', jQuery('#footer').outerHeight() + + + showSpinner: (region) -> + @$(@[region].el).html @spinner diff --git a/sonar-server/src/main/coffee/coding-rules/mockjax.coffee b/sonar-server/src/main/coffee/coding-rules/mockjax.coffee new file mode 100644 index 00000000000..2163fac2a64 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/mockjax.coffee @@ -0,0 +1,332 @@ +define ['jquery.mockjax'], -> + + jQuery.mockjaxSettings.contentType = 'text/json'; + jQuery.mockjaxSettings.responseTime = 250; + + # GET /api/codingrules/app + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/app" + responseText: JSON.stringify + qualityprofiles: [ + { key: 'sonarway', name: 'Sonar Way', lang: 'Java', parent: null }, + { key: 'qualityprofile1', name: 'Quality Profile 1', lang: 'Java', parent: 'sonarway' }, + { key: 'qualityprofile2', name: 'Quality Profile 2', lang: 'JavaScript', parent: 'sonarway' }, + { key: 'qualityprofile3', name: 'Quality Profile 3', lang: 'Java', parent: null }, + ] + languages: + java: 'Java' + javascript: 'JavaScript' + repositories: + 'checkstyle': 'Checkstyle' + 'common-java': 'Common SonarQube' + 'findbugs': 'FindBugs' + 'pmd': 'PMD' + 'pmd-unit-tests': 'PMD Unit Tests' + 'squid': 'SonarQube' + statuses: + 'BETA': 'Beta' + 'DEPRECATED': 'Deprecated' + 'READY': 'Ready' + tags: + 'brain-overload': 'brain-overload' + 'bug': 'bug' + 'comment': 'comment' + 'convention': 'convention' + 'error-handling': 'error-handling' + 'formatting': 'formatting' + 'java8': 'java8' + 'multithreading': 'multithreading' + 'naming': 'naming' + 'pitfall': 'pitfall' + 'security': 'security' + 'size': 'size' + 'unused': 'unused' + 'unused-code': 'unused-code' + characteristics: + '1469': 'Changeability' + '1441': 'Changeability: Architecture related changeability' + '1470': 'Changeability: Data related changeability' + '1475': 'Changeability: Logic related changeability' + '1392': 'Efficiency' + '1377': 'Efficiency: Memory use' + '2965': 'Efficiency: Network use' + '1393': 'Efficiency: Processor use' + '1154': 'Maintainability' + '1022': 'Maintainability: Readability' + '1155': 'Maintainability: Understandability' + '988': 'Portability' + '977': 'Portability: Compiler related portability' + '989': 'Portability: Hardware related portability' + '994': 'Portability: Language related portability' + '1000': 'Portability: OS related portability' + '1006': 'Portability: Software related portability' + '1021': 'Portability: Time zone related portability' + '1551': 'Reliability' + '1496': 'Reliability: Architecture related reliability' + '1552': 'Reliability: Data related reliability' + '1596': 'Reliability: Exception handling' + '1622': 'Reliability: Fault tolerance' + '1629': 'Reliability: Instruction related reliability' + '1759': 'Reliability: Logic related reliability' + '2948': 'Reliability: Resource' + '1874': 'Reliability: Synchronization related reliability' + '1925': 'Reliability: Unit tests' + '975': 'Reusability' + '974': 'Reusability: Modularity' + '976': 'Reusability: Transportability' + '1345': 'Security' + '1335': 'Security: API abuse' + '1346': 'Security: Errors' + '1349': 'Security: Input validation and representation' + '1364': 'Security: Security features' + '1933': 'Testability' + '1932': 'Testability: Integration level testability' + '1934': 'Testability: Unit level testability' + messages: + 'all': 'All' + 'any': 'Any' + 'apply': 'Apply' + 'bold': 'Bold' + 'bulk_change': 'Bulk Change' + 'bulleted_point': 'Bulleted point' + 'cancel': 'Cancel' + 'change': 'Change' + 'code': 'Code' + 'delete': 'Delete' + 'done': 'Done' + 'edit': 'Edit' + 'markdown.helplink': 'Markdown Help' + 'moreCriteria': '+ More Criteria' + 'save': 'Save' + 'search_verb': 'Search' + 'severity': 'Severity' + 'update': 'Update' + + 'severity.BLOCKER': 'Blocker' + 'severity.CRITICAL': 'Critical' + 'severity.MAJOR': 'Major' + 'severity.MINOR': 'Minor' + 'severity.INFO': 'Info' + + 'coding_rules.activate': 'Activate' + 'coding_rules.activate_in': 'Activate In' + 'coding_rules.activate_in_quality_profile': 'Activate In Quality Profile' + 'coding_rules.add_note': 'Add Note' + 'coding_rules.available_since': 'Available Since' + 'coding_rules.bulk_change': 'Bulk Change' + 'coding_rules.change_severity': 'Change Severity' + 'coding_rules.change_severity_in': 'Change Severity In' + 'coding_rules.change_details': 'Change Details of Quality Profile' + 'coding_rules.extend_description': 'Extend Description' + 'coding_rules.deactivate_in': 'Deactivate In' + 'coding_rules.deactivate': 'Deactivate' + 'coding_rules.deactivate_in_quality_profile': 'Deactivate In Quality Profile' + 'coding_rules.found': 'Found' + 'coding_rules._inherits': 'inherits' + 'coding_rules.key': 'Key:' + 'coding_rules.new_search': 'New Search' + 'coding_rules.no_results': 'No Coding Rules' + 'coding_rules.order': 'Order' + 'coding_rules.ordered_by': 'Ordered By' + 'coding_rules.original': 'Original:' + 'coding_rules.page': 'Coding Rules' + 'coding_rules.parameters': 'Parameters' + 'coding_rules.parameters.default_value': 'Default Value:' + 'coding_rules.quality_profiles': 'Quality Profiles' + 'coding_rules.quality_profile': 'Quality Profile' + 'coding_rules.repository': 'Repository:' + 'coding_rules.revert_to_parent_definition': 'Revert to Parent Definition' + 'coding_rules._rules': 'rules' + 'coding_rules.select_tag': 'Select Tag' + + 'coding_rules.filters.activation': 'Activation' + 'coding_rules.filters.activation.active': 'Active' + 'coding_rules.filters.activation.inactive': 'Inactive' + 'coding_rules.filters.activation.help': 'Activation criterion is available when a quality profile is selected' + 'coding_rules.filters.availableSince': 'Available Since' + 'coding_rules.filters.characteristic': 'Characteristic' + 'coding_rules.filters.description': 'Description' + 'coding_rules.filters.quality_profile': 'Quality Profile' + 'coding_rules.filters.inheritance': 'Inheritance' + 'coding_rules.filters.inheritance.inactive': 'Inheritance criterion is available when an inherited quality profile is selected' + 'coding_rules.filters.inheritance.not_inherited': 'Not Inherited' + 'coding_rules.filters.inheritance.inherited': 'Inherited' + 'coding_rules.filters.inheritance.overriden': 'Overriden' + 'coding_rules.filters.key': 'Key' + 'coding_rules.filters.language': 'Language' + 'coding_rules.filters.name': 'Name' + 'coding_rules.filters.repository': 'Repository' + 'coding_rules.filters.severity': 'Severity' + 'coding_rules.filters.status': 'Status' + 'coding_rules.filters.tag': 'Tag' + + 'coding_rules.sort.creation_date': 'Creation Date' + 'coding_rules.sort.name': 'Name' + + + # GET /api/codingrules/search + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/search" + responseText: JSON.stringify + codingrules: [ + { + name: 'Array designators "[]" should be located after the type in method signatures' + language: 'Java' + severity: 'MAJOR' + status: 'DEPRECATED' + }, + { + name: 'Avoid Array Loops' + language: 'Java' + severity: 'CRITICAL' + status: 'READY' + }, + { + name: 'Bad practice - Abstract class defines covariant compareTo() method' + language: 'Java' + severity: 'MAJOR' + status: 'READY' + }, + { + name: 'Correctness - Use of class without a hashCode() method in a hashed data structure' + language: 'Java' + severity: 'MINOR' + status: 'BETA' + }, + { + name: 'Useless Operation On Immutable' + language: 'Java' + severity: 'MAJOR' + status: 'READY' + } + ] + paging: + total: 5 + fTotal: '5' + + + + # GET /api/codingrules/show + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/show" + responseText: JSON.stringify + codingrule: + name: 'Array designators "[]" should be located after the type in method signatures' + language: 'Java' + tags: ['bug', 'comment', 'java8'] + creationDate: '2013-10-15' + fCreationDate: 'Oct 15, 2013' + status: 'DEPRECATED' + repositoryName: 'SonarQube' + repositoryKey: 'squid' + characteristic: 'Reliability' + subcharacteristic: 'Data related reliability' + key: 'S1190' + parameters: [ + { key: 'someParameter', type: 'INT', default: 4, description: 'Some parameter description' } + ] + description: ''' + <p> + According to the Java Language Specification: + </p> + + <pre>For compatibility with older versions of the Java SE platform, + the declaration of a method that returns an array is allowed to place (some or all of) + the empty bracket pairs that form the declaration of the array type after + the formal parameter list. This obsolescent syntax should not be used in new code. + </pre> + + <p>The following code snippet illustrates this rule:</p> + + <pre>public int getVector()[] { /* ... */ } // Non-Compliant + + public int[] getVector() { /* ... */ } // Compliant + + public int[] getMatrix()[] { /* ... */ } // Non-Compliant + + public int[][] getMatrix() { /* ... */ } // Compliant + </pre>''' + extra: '''This note is here <b>only for test purposes</b>.''' + extraRaw: '''This note is here *only for test purposes*.''' + + qualityProfiles: [ + { + name: 'SonarWay' + key: 'sonarway' + severity: 'MINOR' + parameters: [ + { key: 'someParameter', value: 8 } + ] + note: + username: 'Admin Admin' + html: '''<p>This note is here <b>only for test purposes</b>.</p>''' + raw: '''This note is here *only for test purposes*.''' + fCreationDate: 'less than a minute' + }, + { + name: 'Quality Profile 1' + key: 'qualityprofile1' + severity: 'MAJOR' + parameters: [ + { key: 'someParameter', value: 6 } + ] + inherits: 'sonarway' + } + ] + + + + # POST /api/codingrules/extend_description + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/extend_description" + responseText: JSON.stringify + extra: '''This note is here <i>only for test purposes</i>.''' + extraRaw: '''This note is here *only for test purposes*.''' + + + # POST /api/codingrules/bulk_change + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/bulk_change" + + + # POST /api/codingrules/set_tags + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/set_tags" + + + # POST /api/codingrules/activate + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/activate" + + + # POST /api/codingrules/note + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/note" + responseText: JSON.stringify + note: + username: 'Admin Admin' + html: '''<p>This note is here <b>only for test purposes</b>.</p>''' + raw: '''This note is here *only for test purposes*.''' + fCreationDate: 'less than a minute' + + + # GET /api/qualityprofiles/list + jQuery.mockjax + url: "#{baseUrl}/api/qualityprofiles/list" + responseText: JSON.stringify + more: false + results: [ + { id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null }, + { id: 'qp1', text: 'Quality Profile 1', category: 'Java', parent: 'sonarway' }, + { id: 'qp2', text: 'Quality Profile 2', category: 'JavaScript', parent: 'sonarway' }, + { id: 'qp3', text: 'Quality Profile 3', category: 'Java', parent: null }, + ] + + + # GET /api/qualityprofiles/show + jQuery.mockjax + url: "#{baseUrl}/api/qualityprofiles/show" + responseText: JSON.stringify + qualityprofile: + id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null + diff --git a/sonar-server/src/main/coffee/coding-rules/router.coffee b/sonar-server/src/main/coffee/coding-rules/router.coffee new file mode 100644 index 00000000000..1788ce1799e --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/router.coffee @@ -0,0 +1,36 @@ +define [ + 'backbone', +], ( + Backbone, +) -> + + class AppRouter extends Backbone.Router + + routes: + '': 'index' + ':query': 'index' + + + initialize: (options) -> + @app = options.app + + + parseQuery: (query, separator) -> + (query || '').split(separator || '|').map (t) -> + tokens = t.split('=') + key: tokens[0], value: decodeURIComponent(tokens[1]) + + + emptyQuery: -> + @navigate '', trigger: true, replace: true + + + index: (query) -> + params = this.parseQuery(query) + @loadResults(params) + + + loadResults: (params) -> + @app.filterBarView.restoreFromQuery(params) + @app.restoreSorting(params) + @app.fetchFirstPage() diff --git a/sonar-server/src/main/coffee/coding-rules/views/actions-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/actions-view.coffee new file mode 100644 index 00000000000..96e306ed8e8 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/actions-view.coffee @@ -0,0 +1,62 @@ +define [ + 'backbone.marionette' + 'templates/coding-rules' +], ( + Marionette + Templates +) -> + + class CodingRulesStatusView extends Marionette.ItemView + template: Templates['coding-rules-actions'] + + + collectionEvents: + 'all': 'render' + + + ui: + orderChoices: '.navigator-actions-order-choices' + bulkChange: '.navigator-actions-bulk' + + + events: + 'click .navigator-actions-order': 'toggleOrderChoices' + 'click @ui.orderChoices': 'sort' + 'click @ui.bulkChange': 'bulkChange' + + + onRender: -> + unless @collection.sorting.sortText + @collection.sorting.sortText = @$('[data-sort=' + @collection.sorting.sort + ']:first').text() + @render() + + + toggleOrderChoices: (e) -> + e.stopPropagation() + @ui.orderChoices.toggleClass 'open' + if @ui.orderChoices.is '.open' + jQuery('body').on 'click.coding_rules_actions', => + @ui.orderChoices.removeClass 'open' + + + sort: (e) -> + e.stopPropagation() + @ui.orderChoices.removeClass 'open' + jQuery('body').off 'click.coding_rules_actions' + el = jQuery(e.target) + sort = el.data 'sort' + asc = el.data 'asc' + if sort != null && asc != null + @collection.sorting = sort: sort, sortText: el.text(), asc: asc + @options.app.fetchFirstPage() + + + bulkChange: (e) -> + e.stopPropagation() + @options.app.codingRulesBulkChangeDropdownView.toggle() + + + serializeData: -> + _.extend super, + paging: @collection.paging + sorting: @collection.sorting diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee new file mode 100644 index 00000000000..881b70c6293 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee @@ -0,0 +1,51 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class CodingRulesBulkChangeDropdownView extends Marionette.ItemView + className: 'coding-rules-bulk-change-dropdown' + template: Templates['coding-rules-bulk-change-dropdown'] + + + events: + 'click .coding-rules-bulk-change-dropdown-link': 'doAction' + + + doAction: (e) -> + action = jQuery(e.currentTarget).data 'action' + param = jQuery(e.currentTarget).data 'param' + unless param + @options.app.codingRulesBulkChangeView.show action + else + query = @options.app.getQuery() + switch action + when 'activate' then _.extend query, bulk_activate: [param] + when 'deactivate' then _.extend query, bulk_deactivate: [param] + @options.app.codingRulesBulkChangeView.bulkChange query + + + onRender: -> + jQuery('body').append @el + jQuery('body').off('click.bulk-change').on 'click.bulk-change', => @hide() + + + toggle: -> + if @$el.is(':visible') then @hide() else @show() + + + show: -> + @render() + @$el.show() + + + hide: -> + @$el.hide() + + + serializeData: -> + qualityProfile: @options.app.getQualityProfile() + qualityProfileName: @options.app.qualityProfileFilter.view.renderValue()
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee new file mode 100644 index 00000000000..144cbfafb37 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee @@ -0,0 +1,103 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class CodingRulesBulkChangeView extends Marionette.ItemView + className: 'modal' + template: Templates['coding-rules-bulk-change'] + + + events: + 'submit form': 'onSubmit' + 'click #coding-rules-cancel-bulk-change': 'hide' + 'change select': 'enableAction' + + + onRender: -> + @$el.dialog + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + + @$('#coding-rules-bulk-change-activate-on, #coding-rules-bulk-change-deactivate-on').select2 + width: '250px' + minimumResultsForSearch: 1 + + format = (state) -> + return state.text unless state.id + "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}" + @$('#coding-rules-bulk-change-severity').select2 + width: '250px' + minimumResultsForSearch: 999 + formatResult: format + formatSelection: format + escapeMarkup: (m) -> m + + + show: (action) -> + @action = action + @render() + @$el.dialog 'open' + + + hide: -> + @$el.dialog 'close' + + + prepareQuery: -> + query = @options.app.getQuery() + + if @action == 'activate' + if @$('#coding-rules-bulk-change-activate-all').is ':checked' + _.extend query, bulk_activate: _.pluck @options.app.qualityProfiles, 'key' + else + _.extend query, bulk_activate: @$('#coding-rules-bulk-change-activate-on').val() + + if @action == 'deactivate' + if @$('#coding-rules-bulk-change-deactivate-all').is ':checked' + _.extend query, bulk_deactivate: _.pluck @options.app.qualityProfiles, 'key' + else + _.extend query, bulk_deactivate: @$('#coding-rules-bulk-change-deactivate-on').val() + + if @action == 'change-severity' + _.extend query, bulk_change_severity: @$('#coding-rules-bulk-change-severity').val() + + query + + + bulkChange: (query) -> + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/codingrules/bulk_change" + data: query + .done => + @options.app.fetchFirstPage() + + + onSubmit: (e) -> + e.preventDefault() + @bulkChange(@prepareQuery()).done => @hide() + + + serializeData: -> + action: @action + + paging: @options.app.codingRules.paging + qualityProfiles: @options.app.qualityProfiles + + qualityProfile: @options.app.getQualityProfile() + qualityProfileName: @options.app.qualityProfileFilter.view.renderValue() + + activateOnQualityProfiles: @options.app.qualityProfiles + deactivateOnQualityProfiles: _.reject @options.app.qualityProfiles, (q) => q.key == @options.app.getQualityProfile() + + severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'] diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee new file mode 100644 index 00000000000..063b8378929 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee @@ -0,0 +1,47 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class CodingRulesDetailQualityProfileView extends Marionette.ItemView + className: 'coding-rules-detail-quality-profile' + template: Templates['coding-rules-detail-quality-profile'] + + + ui: + change: '.coding-rules-detail-quality-profile-change' + + + events: + 'click @ui.change': 'change' + + + change: -> + @options.app.codingRulesQualityProfileActivationView.model = @model + @options.app.codingRulesQualityProfileActivationView.show() + + + enableUpdate: -> + @ui.update.prop 'disabled', false + + + getParent: -> + return null unless @model.get 'inherits' + @options.qualityProfiles.findWhere(key: @model.get('inherits')).toJSON() + + + enhanceParameters: -> + parent = @getParent() + parameters = @model.get 'parameters' + return parameters unless parent + parameters.map (p) -> + _.extend p, original: _.findWhere(parent.parameters, key: p.key).value + + + serializeData: -> + _.extend super, + parent: @getParent() + parameters: @enhanceParameters()
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee new file mode 100644 index 00000000000..71b0b311062 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee @@ -0,0 +1,14 @@ +define [ + 'backbone.marionette' + 'coding-rules/views/coding-rules-detail-quality-profile-view' +], ( + Marionette, + CodingRulesDetailQualityProfileView +) -> + + class CodingRulesDetailQualityProfilesView extends Marionette.CollectionView + itemView: CodingRulesDetailQualityProfileView + + itemViewOptions: -> + app: @options.app + qualityProfiles: @collection
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee new file mode 100644 index 00000000000..4cf361c7a5c --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee @@ -0,0 +1,131 @@ +define [ + 'backbone', + 'backbone.marionette', + 'coding-rules/views/coding-rules-detail-quality-profiles-view' + 'templates/coding-rules' +], ( + Backbone, + Marionette, + CodingRulesDetailQualityProfilesView, + Templates +) -> + + class CodingRulesDetailView extends Marionette.Layout + template: Templates['coding-rules-detail'] + + + regions: + qualityProfilesRegion: '#coding-rules-detail-quality-profiles' + + + ui: + tagsChange: '.coding-rules-detail-tags-change' + tagInput: '.coding-rules-detail-tag-input' + tagsEdit: '.coding-rules-detail-tag-edit' + tagsEditDone: '.coding-rules-detail-tag-edit-done' + tagsList: '.coding-rules-detail-tag-list' + + descriptionExtra: '#coding-rules-detail-description-extra' + extendDescriptionLink: '#coding-rules-detail-extend-description' + extendDescriptionForm: '#coding-rules-detail-extend-description-form' + extendDescriptionSubmit: '#coding-rules-detail-extend-description-submit' + extendDescriptionText: '#coding-rules-detail-extend-description-text' + extendDescriptionSpinner: '#coding-rules-detail-extend-description-spinner' + cancelExtendDescription: '#coding-rules-detail-extend-description-cancel' + + activateQualityProfile: '#coding-rules-quality-profile-activate' + changeQualityProfile: '.coding-rules-detail-quality-profile-update' + + + events: + 'click @ui.tagsChange': 'changeTags' + 'click @ui.tagsEditDone': 'editDone' + + 'click @ui.extendDescriptionLink': 'showExtendDescriptionForm' + 'click @ui.cancelExtendDescription': 'hideExtendDescriptionForm' + 'click @ui.extendDescriptionSubmit': 'submitExtendDescription' + + 'click @ui.activateQualityProfile': 'activateQualityProfile' + 'click @ui.changeQualityProfile': 'changeQualityProfile' + + + initialize: (options) -> + @qualityProfilesView = new CodingRulesDetailQualityProfilesView + app: @options.app + collection: new Backbone.Collection options.model.get 'qualityProfiles' + + + onRender: -> + @qualityProfilesRegion.show @qualityProfilesView + + @ui.tagInput.select2 + tags: _.difference @options.app.tags, @model.get 'tags' + width: '300px' + @ui.tagsEdit.hide() + + @ui.extendDescriptionForm.hide() + @ui.extendDescriptionSpinner.hide() + + + changeTags: -> + @ui.tagsEdit.show() + @ui.tagsList.hide() + + + editDone: -> + @ui.tagsEdit.html '<i class="spinner"></i>' + tags = @ui.tagInput.val() + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/codingrules/set_tags" + data: tags: tags + .done => + @model.set 'tags', tags.split ',' + @render() + + + showExtendDescriptionForm: -> + @ui.descriptionExtra.hide() + @ui.extendDescriptionForm.show() + + + hideExtendDescriptionForm: -> + @ui.descriptionExtra.show() + @ui.extendDescriptionForm.hide() + + + submitExtendDescription: -> + @ui.extendDescriptionForm.hide() + @ui.extendDescriptionSpinner.show() + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/codingrules/extend_description" + dataType: 'json' + data: text: @ui.extendDescriptionText.val() + .done (r) => + @model.set extra: r.extra, extraRaw: r.extraRaw + @render() + + + getContextQualilyProfile: -> + contextQualityProfile = @options.app.getQualityProfile() + _.findWhere @model.get('qualityProfiles'), key: contextQualityProfile + + + activateQualityProfile: -> + @options.app.codingRulesQualityProfileActivationView.model = null + @options.app.codingRulesQualityProfileActivationView.show() + + + changeQualityProfile: -> + @options.app.codingRulesQualityProfileActivationView.model = new Backbone.Model @getContextQualilyProfile() + @options.app.codingRulesQualityProfileActivationView.show() + + + serializeData: -> + contextQualityProfile = @options.app.getQualityProfile() + + _.extend super, + contextQualityProfile: contextQualityProfile + contextQualityProfileName: @options.app.qualityProfileFilter.view.renderValue() + qualityProfile: @getContextQualilyProfile()
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee new file mode 100644 index 00000000000..c3eb8d48c4e --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee @@ -0,0 +1,12 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class CodingRulesListEmptyView extends Marionette.ItemView + tagName: 'li' + className: 'navigator-results-no-results' + template: Templates['coding-rules-list-empty'] diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee new file mode 100644 index 00000000000..69a9e5fdaff --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee @@ -0,0 +1,34 @@ +define [ + 'backbone.marionette', + 'coding-rules/views/coding-rules-detail-view', + 'templates/coding-rules' +], ( + Marionette, + CodingRulesDetailView, + Templates +) -> + + class CodingRulesListItemView extends Marionette.ItemView + tagName: 'li' + template: Templates['coding-rules-list-item'] + activeClass: 'active' + + + events: -> + 'click': 'showDetail' + + + showDetail: -> + @$el.siblings().removeClass @activeClass + @$el.addClass @activeClass + + @options.app.layout.showSpinner 'detailsRegion' + jQuery.ajax + url: "#{baseUrl}/api/codingrules/show" + .done (r) => + @model.set r.codingrule + @options.app.codingRulesQualityProfileActivationView.rule = @model + detailView = new CodingRulesDetailView + app: @options.app + model: @model + @options.app.layout.detailsRegion.show detailView diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee new file mode 100644 index 00000000000..93db305b2b5 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee @@ -0,0 +1,23 @@ +define [ + 'backbone.marionette', + 'coding-rules/views/coding-rules-list-item-view', + 'coding-rules/views/coding-rules-list-empty-view' +], ( + Marionette, + CodingRulesListItemView, + CodingRulesListEmptyView +) -> + + class CodingRulesListView extends Marionette.CollectionView + tagName: 'ol' + className: 'navigator-results-list' + itemView: CodingRulesListItemView, + emptyView: CodingRulesListEmptyView, + + + itemViewOptions: -> + listView: @, app: @options.app + + + selectFirst: -> + @$el.find('*:first').click() diff --git a/sonar-server/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee new file mode 100644 index 00000000000..70aa55a5daf --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee @@ -0,0 +1,85 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class CodingRulesQualityProfileActivationView extends Marionette.ItemView + className: 'modal' + template: Templates['coding-rules-quality-profile-activation'] + + + ui: + qualityProfileSelect: '#coding-rules-quality-profile-activation-select' + qualityProfileSeverity: '#coding-rules-quality-profile-activation-severity' + qualityProfileActivate: '#coding-rules-quality-profile-activation-activate' + + + events: + 'click #coding-rules-quality-profile-activation-cancel': 'hide' + 'click @ui.qualityProfileActivate': 'activate' + + + activate: -> + @$('.modal-foot').html '<i class="spinner"></i>' + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/codingrules/activate" + data: id: 1 + .done => + jQuery('.navigator-results-list .active').click() + @hide() + + + onRender: -> + @$el.dialog + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + + @ui.qualityProfileSelect.select2 + width: '250px' + minimumResultsForSearch: 5 + + format = (state) -> + return state.text unless state.id + "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}" + + severity = if @model then @model.get 'severity' else @rule.get 'severity' + @ui.qualityProfileSeverity.val severity + @ui.qualityProfileSeverity.select2 + width: '250px' + minimumResultsForSearch: 999 + formatResult: format + formatSelection: format + + + show: -> + @render() + @$el.dialog 'open' + + + hide: -> + @$el.dialog 'close' + + + getAvailableQualityProfiles: -> + _.reject @options.app.qualityProfiles, (profile) => + _.findWhere @rule.get('qualityProfiles'), key: profile.key + + + serializeData: -> + parameters = if @model then @model.get('parameters') else @rule.get('parameters') + + _.extend super, + rule: @rule.toJSON() + parameters: parameters + qualityProfiles: @getAvailableQualityProfiles() + severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'] diff --git a/sonar-server/src/main/coffee/coding-rules/views/filter-bar-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/filter-bar-view.coffee new file mode 100644 index 00000000000..6a719be85aa --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/filter-bar-view.coffee @@ -0,0 +1,71 @@ +define [ + 'navigator/filters/filter-bar', + 'navigator/filters/base-filters', + 'navigator/filters/favorite-filters', + 'navigator/filters/more-criteria-filters', + 'templates/coding-rules' +], ( + FilterBarView, + BaseFilters, + FavoriteFiltersModule, + MoreCriteriaFilters, + Templates +) -> + + class CodingRulesFilterBarView extends FilterBarView + template: Templates['coding-rules-filter-bar'] + + collectionEvents: + 'change:enabled': 'changeEnabled' + + + events: + 'click .navigator-filter-submit': 'search' + + + getQuery: -> + query = {} + @collection.each (filter) -> + _.extend query, filter.view.formatValue() + query + + + onAfterItemAdded: (itemView) -> + if itemView.model.get('type') == FavoriteFiltersModule.FavoriteFilterView + jQuery('.navigator-header').addClass 'navigator-header-favorite' + + + addMoreCriteriaFilter: -> + disabledFilters = this.collection.where enabled: false + if disabledFilters.length > 0 + @moreCriteriaFilter = new BaseFilters.Filter + type: MoreCriteriaFilters.MoreCriteriaFilterView, + enabled: true, + optional: false, + filters: disabledFilters + @collection.add @moreCriteriaFilter + + + changeEnabled: -> + if @moreCriteriaFilter? + disabledFilters = _.reject @collection.where(enabled: false), (filter) -> + filter.get('type') == MoreCriteriaFilters.MoreCriteriaFilterView + + if disabledFilters.length == 0 + @moreCriteriaFilter.set { enabled: false }, { silent: true } + else + @moreCriteriaFilter.set { enabled: true }, { silent: true } + + @moreCriteriaFilter.set { filters: disabledFilters }, { silent: true } + @moreCriteriaFilter.trigger 'change:filters' + + + search: -> + @options.app.state.set + query: this.options.app.getQuery(), + search: true + @options.app.fetchFirstPage() + + + fetchNextPage: -> + @options.app.fetchNextPage() diff --git a/sonar-server/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee new file mode 100644 index 00000000000..896ee64c050 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee @@ -0,0 +1,41 @@ +define [ + 'navigator/filters/choice-filters' + 'coding-rules/views/filters/inheritance-filter-view' +], ( + ChoiceFilters + InheritanceFilterView +) -> + + class DetailsActivationFilterView extends ChoiceFilters.DetailsChoiceFilterView + + onCheck: (e) -> + id = jQuery(e.target).val() + selected = @options.filterView.choices.findWhere checked: true + unless id == selected + @options.filterView.choices.each (item) -> item.set 'checked', item.id == id + else + e.preventDefault() + @updateValue() + @updateLists() + + + + class ActivationFilterView extends InheritanceFilterView + tooltip: 'coding_rules.filters.activation.help' + + + initialize: -> + super detailsView: DetailsActivationFilterView + + + onChangeQualityProfile: -> + qualityProfile = @qualityProfileFilter.get 'value' + if _.isArray(qualityProfile) && qualityProfile.length == 1 then @makeActive() else @makeInactive() + + + makeActive: -> + @choices.each (item) -> item.set 'checked', item.id == 'active' + @detailsView.updateValue() + @detailsView.updateLists() + @render() + super
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee new file mode 100644 index 00000000000..efa29a733ff --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee @@ -0,0 +1,12 @@ +define [ + 'navigator/filters/choice-filters' +], ( + ChoiceFilters +) -> + + class CharacteriticFilterView extends ChoiceFilters.ChoiceFilterView + + initialize: -> + super + @choices.comparator = 'text' + @choices.sort() diff --git a/sonar-server/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee new file mode 100644 index 00000000000..8e575c20268 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee @@ -0,0 +1,52 @@ +define [ + 'navigator/filters/choice-filters' +], ( + ChoiceFilters +) -> + + class InheritanceFilterView extends ChoiceFilters.ChoiceFilterView + tooltip: 'coding_rules.filters.inheritance.inactive' + + + initialize: -> + super + @qualityProfileFilter = @model.get 'qualityProfileFilter' + @listenTo @qualityProfileFilter, 'change:value', @onChangeQualityProfile + @onChangeQualityProfile() + + + onChangeQualityProfile: -> + qualityProfile = @qualityProfileFilter.get 'value' + parentQualityProfile = @qualityProfileFilter.get 'parentQualityProfile' + if _.isArray(qualityProfile) && qualityProfile.length == 1 && parentQualityProfile + @makeActive() + else + @makeInactive() + + + makeActive: -> + @model.set inactive: false, title: '' + @model.trigger 'change:enabled' + @$el.removeClass('navigator-filter-inactive').prop 'title', '' + + + makeInactive: -> + @model.set inactive: true, title: t @tooltip + @model.trigger 'change:enabled' + @choices.each (model) -> model.set 'checked', false + @detailsView.updateLists() + @detailsView.updateValue() + @$el.addClass('navigator-filter-inactive').prop 'title', t @tooltip + + + showDetails: -> + super unless @$el.is '.navigator-filter-inactive' + + + restore: (value) -> + value = value.split(',') if _.isString(value) + if @choices && value.length > 0 + @model.set value: value, enabled: true + @onChangeQualityProfile() + else + @clear() diff --git a/sonar-server/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee new file mode 100644 index 00000000000..eff55a9e618 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee @@ -0,0 +1,51 @@ +define [ + 'navigator/filters/ajax-select-filters' +], ( + AjaxSelectFilters +) -> + + class QualityProfileSuggestions extends AjaxSelectFilters.Suggestions + + url: -> + "#{baseUrl}/api/qualityprofiles/list" + + + + class QualityProfileFilterView extends AjaxSelectFilters.AjaxSelectFilterView + + initialize: -> + super + @choices = new QualityProfileSuggestions + @listenTo @model, 'change:value', @onValueChange + + + onValueChange: -> + @updateParentQualityProfile() + @highlightContext() + + + updateParentQualityProfile: -> + selected = @getSelected() + if selected.length == 1 + @model.set 'parentQualityProfile', selected[0].get('parent') + else + @model.unset 'parentQualityProfile' + + + highlightContext: -> + hasContext = _.isArray(@model.get('value')) && @model.get('value').length > 0 + @$el.toggleClass 'navigator-filter-context', hasContext + + + createRequest: (v) -> + jQuery.ajax + url: baseUrl + '/api/qualityprofiles/show' + type: 'GET' + data: key: v + .done (r) => + @choices.add new Backbone.Model + id: r.qualityprofile.id, + text: r.qualityprofile.text, + parent: r.qualityprofile.parent, + checked: true + diff --git a/sonar-server/src/main/coffee/coding-rules/views/header-view.coffee b/sonar-server/src/main/coffee/coding-rules/views/header-view.coffee new file mode 100644 index 00000000000..ae0f8718732 --- /dev/null +++ b/sonar-server/src/main/coffee/coding-rules/views/header-view.coffee @@ -0,0 +1,18 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules' +], ( + Marionette, + Templates +) -> + + class CodingRulesHeaderView extends Marionette.ItemView + template: Templates['coding-rules-header'] + + + events: + 'click #coding-rules-new-search': 'newSearch' + + + newSearch: -> + @options.app.router.navigate '', trigger: true |