From: Stas Vilchik Date: Thu, 18 Dec 2014 14:17:57 +0000 (+0100) Subject: SONAR-5820 Create a new coding rules page X-Git-Tag: latest-silver-master-#65~434 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4b69d42d7f83aa22853dffbf2b49acda85c7ef99;p=sonarqube.git SONAR-5820 Create a new coding rules page --- diff --git a/server/sonar-web/Gruntfile.coffee b/server/sonar-web/Gruntfile.coffee index 1af2390f85c..45c4af59a1f 100644 --- a/server/sonar-web/Gruntfile.coffee +++ b/server/sonar-web/Gruntfile.coffee @@ -174,6 +174,10 @@ module.exports = (grunt) -> name: 'coding-rules/app' out: '<%= pkg.assets %>build/js/coding-rules/app.js' + codingRulesOld: options: + name: 'coding-rules-old/app' + out: '<%= pkg.assets %>build/js/coding-rules-old/app.js' + issues: options: name: 'issues/app' out: '<%= pkg.assets %>build/js/issues/app.js' @@ -237,6 +241,10 @@ module.exports = (grunt) -> '<%= pkg.sources %>hbs/common/**/*.hbs' '<%= pkg.sources %>hbs/coding-rules/**/*.hbs' ] + '<%= pkg.assets %>js/templates/coding-rules-old.js': [ + '<%= pkg.sources %>hbs/common/**/*.hbs' + '<%= pkg.sources %>hbs/coding-rules-old/**/*.hbs' + ] '<%= pkg.assets %>js/templates/quality-gates.js': [ '<%= pkg.sources %>hbs/quality-gates/**/*.hbs' ] diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/app.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/app.coffee new file mode 100644 index 00000000000..26878007d07 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/app.coffee @@ -0,0 +1,521 @@ +requirejs.config + baseUrl: "#{baseUrl}/js" + + paths: + 'backbone': 'third-party/backbone' + 'backbone.marionette': 'third-party/backbone.marionette' + 'handlebars': 'third-party/handlebars' + + shim: + 'backbone.marionette': + deps: ['backbone'] + exports: 'Marionette' + 'backbone': + exports: 'Backbone' + 'handlebars': + exports: 'Handlebars' + + +requirejs [ + 'backbone', 'backbone.marionette', + + 'coding-rules-old/layout', + 'coding-rules-old/router', + + # views + 'coding-rules-old/views/header-view', + 'coding-rules-old/views/actions-view', + 'coding-rules-old/views/filter-bar-view', + 'coding-rules-old/views/coding-rules-list-view', + 'coding-rules-old/views/coding-rules-detail-view', + 'coding-rules-old/views/coding-rules-bulk-change-view', + 'coding-rules-old/views/coding-rules-quality-profile-activation-view', + 'coding-rules-old/views/coding-rules-bulk-change-dropdown-view', + 'coding-rules-old/views/coding-rules-facets-view', + 'coding-rules-old/views/coding-rules-custom-rule-creation-view', + 'coding-rules-old/views/coding-rules-manual-rule-creation-view', + + # filters + 'navigator/filters/base-filters', + 'navigator/filters/choice-filters', + 'navigator/filters/string-filters', + 'navigator/filters/date-filter-view', + 'navigator/filters/read-only-filters', + 'coding-rules-old/views/filters/query-filter-view', + 'coding-rules-old/views/filters/quality-profile-filter-view', + 'coding-rules-old/views/filters/inheritance-filter-view', + 'coding-rules-old/views/filters/active-severities-filter-view', + 'coding-rules-old/views/filters/activation-filter-view', + 'coding-rules-old/views/filters/characteristic-filter-view', + 'coding-rules-old/views/filters/repository-filter-view', + 'coding-rules-old/views/filters/tag-filter-view', + 'coding-rules-old/views/filters/language-filter-view', + + 'common/handlebars-extensions' +], ( + Backbone, Marionette, + + CodingRulesLayout, + CodingRulesRouter, + + # views + CodingRulesHeaderView, + CodingRulesActionsView, + CodingRulesFilterBarView, + CodingRulesListView, + CodingRulesDetailView, + CodingRulesBulkChangeView, + CodingRulesQualityProfileActivationView, + CodingRulesBulkChangeDropdownView, + CodingRulesFacetsView, + CodingRulesCustomRuleCreationView, + CodingRulesManualRuleCreationView, + + # filters + BaseFilters, + ChoiceFilters, + StringFilterView, + DateFilterView, + ReadOnlyFilterView, + QueryFilterView, + QualityProfileFilterView, + InheritanceFilterView, + ActiveSeveritiesFilterView, + ActivationFilterView, + CharacteristicFilterView, + RepositoryFilterView, + TagFilterView, + LanguageFilterView +) -> + + # 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 '. ' + else + text = t 'default_error_message' + 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 = (params) -> + sort = _.findWhere(params, key: 'sort') + asc = _.findWhere(params, key: 'asc') + + if (sort && asc) + @codingRules.sorting = + sort: sort.value + asc: asc.value =='true' + + + App.restoreDefaultSorting = -> + params = [] + params.push(key: 'sort', value: 'createdAt') + params.push(key: 'asc', value: false) + @restoreSorting params + + + App.storeQuery = (query, sorting) -> + if sorting && sorting.sort + _.extend query, + s: 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 { p: @pageIndex, ps: 25, facets: firstPage }, query + + if @codingRules.sorting && @codingRules.sorting.sort + _.extend fetchQuery, + s: @codingRules.sorting.sort, + asc: @codingRules.sorting.asc + + @storeQuery query, @codingRules.sorting + + # Optimize requested fields + _.extend fetchQuery, f: 'name,lang,status,tags,sysTags' + + if @codingRulesListView + scrollOffset = jQuery('.navigator-results')[0].scrollTop + else + scrollOffset = 0 + + @layout.showSpinner 'resultsRegion' + @layout.showSpinner 'facetsRegion' if firstPage + + + jQuery.ajax + url: "#{baseUrl}/api/rules/search" + data: fetchQuery + .done (r) => + _.map(r.rules, (rule) -> + rule.language = App.languages[rule.lang] + ) + + @codingRules.paging = + total: r.total + pageIndex: r.p + pageSize: r.ps + pages: 1 + (r.total / r.ps) + + if @codingRulesListView + @codingRulesListView.close() + + if firstPage + @codingRules.reset r.rules + @codingRulesListView = new CodingRulesListView + app: @ + collection: @codingRules + else + @codingRulesListView.unbindEvents() + @codingRules.add r.rules + + @layout.resultsRegion.show @codingRulesListView + + + if @codingRules.isEmpty() + @layout.detailsRegion.reset() + else if firstPage + @codingRulesListView.selectFirst() + else + @codingRulesListView.selectCurrent() + + if firstPage + @codingRulesFacetsView = new CodingRulesFacetsView + app: @ + collection: new Backbone.Collection r.facets, comparator: 'property' + @layout.facetsRegion.show @codingRulesFacetsView + @filterBarView.restoreFromWsQuery query + @codingRulesFacetsView.restoreFromQuery query + else + jQuery('.navigator-results')[0].scrollTop = scrollOffset + + @layout.onResize() + + + + App.facetLabel = (property, value) -> + return value unless App.facetPropertyToLabels[property] + App.facetPropertyToLabels[property](value) + + + 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 + + + App.getQualityProfilesForLanguage = (language_key) -> + _.filter App.qualityProfiles, (p) => p.lang == language_key + + App.getQualityProfileByKey = (profile_key) -> + _.findWhere App.qualityProfiles, key: profile_key + + + App.getSubcharacteristicName = (name) -> + (App.characteristics[name] || '').replace ': ', ' > ' + + + App.showRule = (ruleKey) -> + App.layout.showSpinner 'detailsRegion' + jQuery.ajax + url: "#{baseUrl}/api/rules/show" + data: + key: ruleKey + actives: true + .done (r) => + rule = new Backbone.Model(r.rule) + App.codingRulesQualityProfileActivationView.rule = rule + App.detailView = new CodingRulesDetailView + app: App + model: rule + actives: r.actives + App.layout.detailsRegion.show App.detailView + + + App.manualRepository = -> + key: 'manual' + name: 'Manual Rules' + language: 'none' + + + App.createManualRule = -> + App.codingRulesManualRuleCreationView.model = new Backbone.Model() + App.codingRulesManualRuleCreationView.show() + + + # Construct layout + App.addInitializer -> + @layout = new CodingRulesLayout app: @ + jQuery('#content').append @layout.render().el + @layout.onResize() + + + # Construct header + App.addInitializer -> + @codingRulesHeaderView = new CodingRulesHeaderView app: @ + @layout.headerRegion.show @codingRulesHeaderView + + + # Define coding rules + App.addInitializer -> + @codingRules = new Backbone.Collection + @restoreDefaultSorting() + + + # 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: @ + + + # Construct custom rule creation view + App.addInitializer -> + @codingRulesCustomRuleCreationView = new CodingRulesCustomRuleCreationView app: @ + + + # Construct custom rule creation view + App.addInitializer -> + @codingRulesManualRuleCreationView = new CodingRulesManualRuleCreationView app: @ + + # Define filters + App.addInitializer -> + @filters = new BaseFilters.Filters + + @queryFilter = new BaseFilters.Filter + property: 'q' + type: QueryFilterView + size: 50 + @filters.add @queryFilter + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.severity' + property: 'severities' + type: ChoiceFilters.ChoiceFilterView + optional: true + 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: TagFilterView + optional: true + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.characteristic' + property: 'debt_characteristics' + type: CharacteristicFilterView + choices: @characteristics + multiple: false + optional: true + + @qualityProfileFilter = new BaseFilters.Filter + name: t 'coding_rules.filters.quality_profile' + property: 'qprofile' + type: QualityProfileFilterView + app: @ + choices: @qualityProfiles + multiple: false + @filters.add @qualityProfileFilter + + @activationFilter = new BaseFilters.Filter + name: t 'coding_rules.filters.activation' + property: 'activation' + type: ActivationFilterView + enabled: false + optional: true + multiple: false + qualityProfileFilter: @qualityProfileFilter + choices: + true: t 'coding_rules.filters.activation.active' + false: t 'coding_rules.filters.activation.inactive' + @filters.add @activationFilter + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.active_severity' + property: 'active_severities' + type: ActiveSeveritiesFilterView + enabled: false + optional: true + qualityProfileFilter: @qualityProfileFilter + 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' + + @languageFilter = new BaseFilters.Filter + name: t 'coding_rules.filters.language' + property: 'languages' + type: LanguageFilterView + app: @ + choices: @languages + optional: true + @filters.add @languageFilter + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.availableSince' + property: 'available_since' + type: DateFilterView + 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: + 'NONE': t 'coding_rules.filters.inheritance.not_inherited' + 'INHERITED': t 'coding_rules.filters.inheritance.inherited' + 'OVERRIDES': t 'coding_rules.filters.inheritance.overriden' + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.repository' + property: 'repositories' + type: RepositoryFilterView + enabled: false + optional: true + app: @ + choices: @repositories + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.status' + property: 'statuses' + type: ChoiceFilters.ChoiceFilterView + enabled: false + optional: true + choices: @statuses + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.template' + property: 'is_template' + type: ChoiceFilters.ChoiceFilterView + optional: true + multiple: false + choices: + 'true': t 'coding_rules.filters.template.is_template' + 'false': t 'coding_rules.filters.template.is_not_template' + + @filters.add new BaseFilters.Filter + name: t 'coding_rules.filters.key' + property: 'rule_key' + type: ReadOnlyFilterView + enabled: false + optional: true + + + @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/rules/app" + .done (r) -> + App.appState = new Backbone.Model + App.state = new Backbone.Model + App.canWrite = r.canWrite + App.qualityProfiles = _.sortBy r.qualityprofiles, ['name', 'lang'] + App.languages = _.extend r.languages, none: 'None' + _.map App.qualityProfiles, (profile) -> + profile.language = App.languages[profile.lang] + App.repositories = r.repositories + App.repositories.push App.manualRepository() + App.statuses = r.statuses + App.characteristics = r.characteristics + + App.facetPropertyToLabels = + 'languages': (value) -> App.languages[value] + 'repositories': (value) -> + repo = _.findWhere(App.repositories, key: value) + other_repo_with_same_name = _.find(App.repositories, (repos) -> repos.name == repo.name && repos.key != repo.key) + if other_repo_with_same_name + App.languages[repo.language] + ' ' + repo.name + else + repo.name + + # Message bundles + l10nXHR = window.requestMessages() + + jQuery.when(l10nXHR, appXHR).done -> + # Remove the initial spinner + jQuery('#coding-rules-page-loader').remove() + + # Start the application + App.start() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/layout.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/layout.coffee new file mode 100644 index 00000000000..459c11d337f --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/layout.coffee @@ -0,0 +1,90 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class AppLayout extends Marionette.Layout + className: 'navigator coding-rules-navigator' + template: Templates['coding-rules-layout'] + storageKey: 'codingRulesResultsWidth' + + + regions: + headerRegion: '.navigator-header' + actionsRegion: '.navigator-actions' + resultsRegion: '.navigator-results' + detailsRegion: '.navigator-details' + filtersRegion: '.navigator-filters' + facetsRegion: '.navigator-facets' + + + ui: + side: '.navigator-side' + results: '.navigator-results' + details: '.navigator-details' + resizer: '.navigator-resizer' + + + initialize: -> + jQuery(window).on 'resize', => @onResize() + + @isResize = false + jQuery('body').on 'mousemove', (e) => @processResize(e) + jQuery('body').on 'mouseup', => @stopResize() + + + onRender: -> + @ui.resizer.on 'mousedown', (e) => @startResize(e) + + resultsWidth = localStorage.getItem @storageKey + if resultsWidth + @$(@resultsRegion.el).width +resultsWidth + @ui.side.width +resultsWidth + 20 + + + onResize: -> + footerEl = jQuery('#footer') + footerHeight = footerEl.outerHeight true + + resultsEl = @ui.results + resultsHeight = jQuery(window).height() - resultsEl.offset().top - + parseInt(resultsEl.css('margin-bottom'), 10) - footerHeight + resultsEl.height resultsHeight + + detailsEl = @ui.details + detailsWidth = jQuery(window).width() - detailsEl.offset().left - + parseInt(detailsEl.css('margin-right'), 10) + detailsHeight = jQuery(window).height() - detailsEl.offset().top - + parseInt(detailsEl.css('margin-bottom'), 10) - footerHeight + detailsEl.width(detailsWidth).height detailsHeight + + + showSpinner: (region) -> + @[region].show new Marionette.ItemView + template: _.template('') + + + startResize: (e) -> + @isResize = true + @originalWidth = @ui.results.width() + @x = e.clientX + jQuery('html').attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false) + + + processResize: (e) -> + if @isResize + delta = e.clientX - @x + @$(@resultsRegion.el).width @originalWidth + delta + @ui.side.width @originalWidth + 20 + delta + localStorage.setItem @storageKey, @ui.results.width() + @onResize() + + + stopResize: -> + if @isResize + jQuery('html').attr('unselectable', 'off').css('user-select', 'text').off('selectstart') + @isResize = false + true diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/mockjax.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/mockjax.coffee new file mode 100644 index 00000000000..30f37ba626b --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/mockjax.coffee @@ -0,0 +1,364 @@ +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' + 'are_you_sure': 'Are you sure?' + '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.activate_in_all_quality_profiles': 'Activate In All {0} Profiles' + '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.deactivate_in_all_quality_profiles': 'Deactivate In All {0} Profiles' + 'coding_rules.found': 'Found' + 'coding_rules.inherits': '"{0}" inherits "{1}"' + 'coding_rules.key': 'Key:' + 'coding_rules.new_search': 'New Search' + 'coding_rules.no_results': 'No Coding Rules' + 'coding_rules.no_tags': 'No tags' + '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.permalink': 'Permalink' + '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' + facets: [ + { + name: 'Languages' + property: 'languages' + values: [ + { key: 'java', text: 'Java', stat: 45 } + { key: 'javascript', text: 'JavaScript', stat: 21 } + ] + } + { + name: 'Tags' + property: 'tags' + values: [ + { key: 'brain-overload', text: 'brain-overload', stat: 8 } + { key: 'bug', text: 'bug', stat: 7 } + { key: 'comment', text: 'comment', stat: 7 } + { key: 'convention', text: 'convention', stat: 6 } + { key: 'error-handling', text: 'error-handling', stat: 5 } + ] + } + { + name: 'Repositories' + property: 'repositories' + values: [ + { key: 'squid', text: 'SonarQube', stat: 57 } + { key: 'pmd', text: 'PMD', stat: 17 } + ] + } + ] + + + + + # 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' + 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' } + { key: 'xpath', type: 'TEXT', description: 'XPath, the XML Path Language, is a query language for selecting nodes from an XML document. In addition, XPath may be used to compute values (e.g., strings, numbers, or Boolean values) from the content of an XML document. XPath was defined by the World Wide Web Consortium (W3C).' } + ] + description: ''' +

+ According to the Java Language Specification: +

+ +
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.
+            
+ +

The following code snippet illustrates this rule:

+ +
public int getVector()[] { /* ... */ }    // Non-Compliant
+
+            public int[] getVector() { /* ... */ }    // Compliant
+
+            public int[] getMatrix()[] { /* ... */ }  // Non-Compliant
+
+            public int[][] getMatrix() { /* ... */ }  // Compliant
+            
''' + extra: '''This note is here only for test purposes.''' + extraRaw: '''This note is here *only for test purposes*.''' + + qualityProfiles: [ + { + name: 'SonarWay' + key: 'sonarway' + severity: 'MINOR' + parameters: [ + { key: 'someParameter', value: 8 } + { key: 'xpath', value: '/child::html/child::body/child::*/child::span[attribute::class]' } + ] + }, + { + name: 'Quality Profile 1' + key: 'qualityprofile1' + severity: 'MAJOR' + parameters: [ + { key: 'someParameter', value: 6 } + { key: 'xpath', value: '/html/body/*/span[@class]' } + ] + inherits: 'sonarway' + } + ] + + + + # POST /api/codingrules/extend_description + jQuery.mockjax + url: "#{baseUrl}/api/codingrules/extend_description" + responseText: JSON.stringify + extra: '''This note is here only for test purposes.''' + 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: '''

This note is here only for test purposes.

''' + 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/server/sonar-web/src/main/coffee/coding-rules-old/router.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/router.coffee new file mode 100644 index 00000000000..fe49b73dbbd --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/router.coffee @@ -0,0 +1,39 @@ +define [ + 'backbone', +], ( + Backbone, +) -> + + class AppRouter extends Backbone.Router + + routes: + '': 'emptyQuery' + ':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: -> + @app.restoreDefaultSorting() + @index('') + + + index: (query) -> + params = this.parseQuery(query) + @loadResults(params) + + + loadResults: (params) -> + @app.filterBarView.restoreFromQuery(params) + if @app.codingRulesFacetsView + @app.codingRulesFacetsView.restoreFromQuery(params) + @app.restoreSorting(params) + @app.fetchFirstPage() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/actions-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/actions-view.coffee new file mode 100644 index 00000000000..b8559cb2639 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/actions-view.coffee @@ -0,0 +1,64 @@ +define [ + 'backbone.marionette' + 'templates/coding-rules-old' +], ( + 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 + while not @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, + canWrite: @options.app.canWrite + paging: @collection.paging + sorting: @collection.sorting diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-dropdown-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-dropdown-view.coffee new file mode 100644 index 00000000000..0a1ee73f23d --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-dropdown-view.coffee @@ -0,0 +1,55 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + 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' + @options.app.codingRulesBulkChangeView.show action, param + + + onRender: -> + jQuery('body').append @el + jQuery('body').off('click.bulk-change').on 'click.bulk-change', => @hide() + @$el.css + top: jQuery('.navigator-actions').offset().top + jQuery('.navigator-actions').height() + 1 + left: jQuery('.navigator-actions').offset().left + jQuery('.navigator-actions').outerWidth() - @$el.outerWidth() + + + toggle: -> + if @$el.is(':visible') then @hide() else @show() + + + show: -> + @render() + @$el.show() + + + hide: -> + @$el.hide() + + + serializeData: -> + languages = @options.app.languageFilter.get('value') + activationValues = @options.app.activationFilter.get('value') or [] + qualityProfile = @options.app.getQualityProfile() + + qualityProfile: qualityProfile + qualityProfileName: @options.app.qualityProfileFilter.view.renderValue() + singleLanguage: _.isArray(languages) and languages.length == 1 + language: @options.app.languageFilter.view.renderValue() + allowActivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'false') + allowDeactivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'true') diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-view.coffee new file mode 100644 index 00000000000..16b2689db4b --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-bulk-change-view.coffee @@ -0,0 +1,123 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesBulkChangeView extends Marionette.ItemView + template: Templates['coding-rules-bulk-change'] + + ui: + modalFooter: '.modal-foot' + modalError: '.modal-error' + modalWarning: '.modal-warning' + modalNotice: '.modal-notice' + modalField: '.modal-field' + codingRulesSubmitBulkChange: '#coding-rules-submit-bulk-change' + codingRulesCancelBulkChange: '#coding-rules-cancel-bulk-change' + codingRulesCloseBulkChange: '#coding-rules-close-bulk-change' + + events: + 'submit form': 'onSubmit' + 'click @ui.codingRulesCancelBulkChange': 'hide' + 'click @ui.codingRulesCloseBulkChange': 'close' + '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-profile').select2 + width: '250px' + minimumResultsForSearch: 1 + + show: (action, param = null) -> + @action = action + @profile = param + @render() + @$el.dialog 'open' + + + hide: -> + @$el.dialog 'close' + + + close: -> + @options.app.fetchFirstPage() + @hide() + false + + + prepareQuery: -> + _.extend @options.app.getQuery(), + wsAction: @action + profile_key: @$('#coding-rules-bulk-change-profile').val() or @profile + + + bulkChange: (query) -> + wsAction = query.wsAction + query = _.omit(query, 'wsAction') + + @ui.modalError.hide() + @ui.modalWarning.hide() + @ui.modalNotice.hide() + + origFooter = @ui.modalFooter.html() + @ui.modalFooter.html '' + + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualityprofiles/#{wsAction}_rules" + data: query + .done (r) => + @ui.modalField.hide() + if (r.failed) + @ui.modalWarning.show() + @ui.modalWarning.html tp('coding_rules.bulk_change.warning', r.succeeded, r.failed) + else + @ui.modalNotice.show() + @ui.modalNotice.html tp('coding_rules.bulk_change.success', r.succeeded) + + @ui.modalFooter.html origFooter + @$(@ui.codingRulesSubmitBulkChange.selector).hide() + @$(@ui.codingRulesCancelBulkChange.selector).hide() + @$(@ui.codingRulesCloseBulkChange.selector).show() + @$(@ui.codingRulesCloseBulkChange.selector).focus() + .fail => + @ui.modalFooter.html origFooter + + + onSubmit: (e) -> + e.preventDefault() + @bulkChange(@prepareQuery()) + + + getAvailableQualityProfiles: -> + languages = @options.app.languageFilter.get('value') + singleLanguage = _.isArray(languages) && languages.length == 1 + + if singleLanguage + @options.app.getQualityProfilesForLanguage(languages[0]) + else + @options.app.qualityProfiles + + serializeData: -> + action: @action + + paging: @options.app.codingRules.paging + qualityProfiles: @options.app.qualityProfiles + + qualityProfile: @profile + qualityProfileName: @options.app.qualityProfileFilter.view.renderValue() + + availableQualityProfiles: @getAvailableQualityProfiles() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-custom-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-custom-rule-creation-view.coffee new file mode 100644 index 00000000000..0efc2a00beb --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-custom-rule-creation-view.coffee @@ -0,0 +1,179 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesCustomRuleCreationView extends Marionette.ItemView + className: 'coding-rules-modal' + template: Templates['coding-rules-custom-rule-creation'] + + + ui: + customRuleCreationKey: '#coding-rules-custom-rule-creation-key' + customRuleCreationName: '#coding-rules-custom-rule-creation-name' + customRuleCreationHtmlDescription: '#coding-rules-custom-rule-creation-html-description' + customRuleCreationSeverity: '#coding-rules-custom-rule-creation-severity' + customRuleCreationStatus: '#coding-rules-custom-rule-creation-status' + customRuleCreationParameters: '[name]' + customRuleCreationCreate: '#coding-rules-custom-rule-creation-create' + customRuleCreationReactivate: '#coding-rules-custom-rule-creation-reactivate' + modalFoot: '.modal-foot' + + + events: + 'input @ui.customRuleCreationName': 'generateKey' + 'keydown @ui.customRuleCreationName': 'generateKey' + 'keyup @ui.customRuleCreationName': 'generateKey' + + 'input @ui.customRuleCreationKey': 'flagKey' + 'keydown @ui.customRuleCreationKey': 'flagKey' + 'keyup @ui.customRuleCreationKey': 'flagKey' + + 'click #coding-rules-custom-rule-creation-cancel': 'hide' + 'click @ui.customRuleCreationCreate': 'create' + 'click @ui.customRuleCreationReactivate': 'reactivate' + + + generateKey: -> + unless @keyModifiedByUser + if @ui.customRuleCreationKey + generatedKey = @ui.customRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_') + @ui.customRuleCreationKey.val generatedKey + + flagKey: -> + @keyModifiedByUser = true + # Cannot use @ui.customRuleCreationReactivate.hide() directly since it was not there at initial render + jQuery(@ui.customRuleCreationReactivate.selector).hide() + + + create: -> + action = 'create' + if @model and @model.has 'key' + action = 'update' + + postData = + name: @ui.customRuleCreationName.val() + markdown_description: @ui.customRuleCreationHtmlDescription.val() + severity: @ui.customRuleCreationSeverity.val() + status: @ui.customRuleCreationStatus.val() + + if @model && @model.has 'key' + postData.key = @model.get 'key' + else + postData.template_key = @templateRule.get 'key' + postData.custom_key = @ui.customRuleCreationKey.val() + postData.prevent_reactivation = true + + params = @ui.customRuleCreationParameters.map(-> + node = jQuery(@) + value = node.val() + if !value and action == 'create' + value = node.prop('placeholder') || '' + key: node.prop('name'), value: value).get() + + postData.params = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';') + @sendRequest(action, postData) + + + reactivate: -> + postData = + name: @existingRule.name + markdown_description: @existingRule.mdDesc + severity: @existingRule.severity + status: @existingRule.status + template_key: @existingRule.templateKey + custom_key: @ui.customRuleCreationKey.val() + prevent_reactivation: false + + params = @existingRule.params + postData.params = (params.map (param) -> param.key + '=' + param.defaultValue).join(';') + + @sendRequest('create', postData) + + + sendRequest: (action, postData) -> + @$('.modal-error').hide() + @$('.modal-warning').hide() + + origFooter = @ui.modalFoot.html() + @ui.modalFoot.html '' + + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/rules/" + action + data: postData + error: () -> + .done (r) => + delete @templateRule + @options.app.showRule r.rule.key + @hide() + .fail (jqXHR, textStatus, errorThrown) => + if jqXHR.status == 409 + @existingRule = jqXHR.responseJSON.rule + @$('.modal-warning').show() + @ui.modalFoot.html Templates['coding-rules-custom-rule-reactivation'](@) + else + jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown) + @ui.modalFoot.html origFooter + + + onRender: -> + @$el.dialog + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + + @keyModifiedByUser = false + + format = (state) -> + return state.text unless state.id + " #{state.text}" + + severity = (@model && @model.get 'severity') || @templateRule.get 'severity' + @ui.customRuleCreationSeverity.val severity + @ui.customRuleCreationSeverity.select2 + width: '250px' + minimumResultsForSearch: 999 + formatResult: format + formatSelection: format + + status = (@model && @model.get 'status') || @templateRule.get 'status' + @ui.customRuleCreationStatus.val status + @ui.customRuleCreationStatus.select2 + width: '250px' + minimumResultsForSearch: 999 + + + show: -> + @render() + @$el.dialog 'open' + + + hide: -> + @$el.dialog 'close' + + + serializeData: -> + params = {} + if @templateRule + params = @templateRule.get 'params' + else if @model and @model.has 'params' + params = @model.get('params').map (p) -> + _.extend p, + value: p.defaultValue + + _.extend super, + change: @model && @model.has 'key' + params: params + severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'] + statuses: _.map @options.app.statuses, (value, key) -> + id: key + text: value diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-debt-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-debt-popup-view.coffee new file mode 100644 index 00000000000..3331b7d3fab --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-debt-popup-view.coffee @@ -0,0 +1,16 @@ +define [ + 'backbone.marionette' + 'templates/coding-rules-old' + 'common/popup' +], ( + Marionette + Templates + Popup +) -> + + class CodingRulesDebtPopupView extends Popup + template: Templates['coding-rules-debt-popup'] + + serializeData: -> + _.extend super, + subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar') diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rule-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rule-view.coffee new file mode 100644 index 00000000000..84c1f332153 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rule-view.coffee @@ -0,0 +1,42 @@ +define [ + 'backbone.marionette' + 'templates/coding-rules-old' +], ( + Marionette + Templates +) -> + + class CodingRulesDetailCustomRuleView extends Marionette.ItemView + tagName: 'tr' + className: 'coding-rules-detail-custom-rule' + template: Templates['coding-rules-detail-custom-rule'] + + ui: + delete: '.coding-rules-detail-custom-rule-delete' + + events: + 'click @ui.delete': 'delete' + + delete: -> + confirmDialog + title: t 'delete' + html: t 'are_you_sure' + yesHandler: => + origEl = @$el.html() + @$el.html '' + + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/rules/delete" + data: + key: @model.get 'key' + .done => + templateKey = @options.templateKey or @options.templateRule.get 'key' + @options.app.showRule templateKey + .fail => + @$el.html origEl + + serializeData: -> + _.extend super, + templateRule: @options.templateRule + canWrite: @options.app.canWrite diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rules-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rules-view.coffee new file mode 100644 index 00000000000..b5df8e77c0f --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-custom-rules-view.coffee @@ -0,0 +1,16 @@ +define [ + 'backbone.marionette' + 'coding-rules-old/views/coding-rules-detail-custom-rule-view' +], ( + Marionette + CodingRulesDetailCustomRuleView +) -> + + class CodingRulesDetailCustomRulesView extends Marionette.CollectionView + tagName: 'table' + className: 'width100' + itemView: CodingRulesDetailCustomRuleView + + itemViewOptions: -> + app: @options.app + templateRule: @options.templateRule diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profile-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profile-view.coffee new file mode 100644 index 00000000000..ef8a98db380 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profile-view.coffee @@ -0,0 +1,101 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesDetailQualityProfileView extends Marionette.ItemView + className: 'coding-rules-detail-quality-profile' + template: Templates['coding-rules-detail-quality-profile'] + + + modelEvents: + 'change': 'render' + + + ui: + change: '.coding-rules-detail-quality-profile-change' + revert: '.coding-rules-detail-quality-profile-revert' + deactivate: '.coding-rules-detail-quality-profile-deactivate' + + + events: + 'click @ui.change': 'change' + 'click @ui.revert': 'revert' + 'click @ui.deactivate': 'deactivate' + + + change: -> + @options.app.codingRulesQualityProfileActivationView.model = @model + @options.app.codingRulesQualityProfileActivationView.show() + + + revert: -> + ruleKey = @options.rule.get('key') + confirmDialog + title: t 'coding_rules.revert_to_parent_definition' + html: tp 'coding_rules.revert_to_parent_definition.confirm', @getParent().name + yesHandler: => + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualityprofiles/activate_rule" + data: + profile_key: @model.get('qProfile') + rule_key: ruleKey + reset: true + .done => + @options.app.showRule ruleKey + + + deactivate: -> + ruleKey = @options.rule.get('key') + myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile')) + confirmDialog + title: t 'coding_rules.deactivate' + html: tp 'coding_rules.deactivate.confirm', myProfile.name + yesHandler: => + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualityprofiles/deactivate_rule" + data: + profile_key: @model.get('qProfile') + rule_key: ruleKey + .done => + @options.app.showRule ruleKey + + + enableUpdate: -> + @ui.update.prop 'disabled', false + + + getParent: -> + return null unless @model.get('inherit') && @model.get('inherit') != 'NONE' + myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile')) + parentKey = myProfile.parentKey + parent = _.extend {}, _.findWhere(@options.app.qualityProfiles, key: parentKey) + parentActiveInfo = @model.collection.findWhere(qProfile: parentKey) or new Backbone.Model() + _.extend parent, parentActiveInfo.toJSON() + parent + + + enhanceParameters: -> + parent = @getParent() + params = _.sortBy(@model.get('params'), 'key') + return params unless parent + params.map (p) -> + parentParam = _.findWhere(parent.params, key: p.key) + if parentParam + _.extend p, original: _.findWhere(parent.params, key: p.key).value + else + p + + + serializeData: -> + hash = _.extend super, + parent: @getParent() + parameters: @enhanceParameters() + canWrite: @options.app.canWrite + templateKey: @options.rule.get 'templateKey' + isTemplate: @options.rule.get 'isTemplate' diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profiles-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profiles-view.coffee new file mode 100644 index 00000000000..b26bbeeef20 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-quality-profiles-view.coffee @@ -0,0 +1,15 @@ +define [ + 'backbone.marionette' + 'coding-rules-old/views/coding-rules-detail-quality-profile-view' +], ( + Marionette, + CodingRulesDetailQualityProfileView +) -> + + class CodingRulesDetailQualityProfilesView extends Marionette.CollectionView + itemView: CodingRulesDetailQualityProfileView + + itemViewOptions: -> + app: @options.app + rule: @options.rule + qualityProfiles: @collection diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-view.coffee new file mode 100644 index 00000000000..20bf8c789b5 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-detail-view.coffee @@ -0,0 +1,344 @@ +define [ + 'backbone' + 'backbone.marionette' + 'coding-rules-old/views/coding-rules-detail-quality-profiles-view' + 'coding-rules-old/views/coding-rules-detail-quality-profile-view' + 'coding-rules-old/views/coding-rules-detail-custom-rules-view' + 'coding-rules-old/views/coding-rules-detail-custom-rule-view' + 'coding-rules-old/views/coding-rules-parameter-popup-view' + 'coding-rules-old/views/coding-rules-debt-popup-view' + 'templates/coding-rules-old' +], ( + Backbone + Marionette + CodingRulesDetailQualityProfilesView + CodingRulesDetailQualityProfileView + CodingRulesDetailCustomRulesView + CodingRulesDetailCustomRuleView + CodingRulesParameterPopupView + CodingRulesDebtPopupView + Templates +) -> + + class CodingRulesDetailView extends Marionette.Layout + template: Templates['coding-rules-detail'] + + + regions: + qualityProfilesRegion: '#coding-rules-detail-quality-profiles' + customRulesRegion: '.coding-rules-detail-custom-rules-section' + customRulesListRegion: '#coding-rules-detail-custom-rules' + contextRegion: '.coding-rules-detail-context' + + + 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' + tagsEditCancel: '.coding-rules-details-tag-edit-cancel' + tagsList: '.coding-rules-detail-tag-list' + + subcharacteristic: '.coding-rules-subcharacteristic' + + 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' + extendDescriptionRemove: '#coding-rules-detail-extend-description-remove' + 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' + activateContextQualityProfile: '.coding-rules-detail-quality-profile-activate' + changeQualityProfile: '.coding-rules-detail-quality-profile-update' + createCustomRule: '#coding-rules-custom-rules-create' + changeCustomRule: '#coding-rules-detail-custom-rule-change' + changeManualRule: '#coding-rules-detail-manual-rule-change' + deleteCustomRule: '#coding-rules-detail-rule-delete' + + + events: + 'click @ui.tagsChange': 'changeTags' + 'click @ui.tagsEditDone': 'editDone' + 'click @ui.tagsEditCancel': 'cancelEdit' + + 'click @ui.extendDescriptionLink': 'showExtendDescriptionForm' + 'click @ui.cancelExtendDescription': 'hideExtendDescriptionForm' + 'click @ui.extendDescriptionSubmit': 'submitExtendDescription' + 'click @ui.extendDescriptionRemove': 'removeExtendedDescription' + + 'click @ui.activateQualityProfile': 'activateQualityProfile' + 'click @ui.activateContextQualityProfile': 'activateContextQualityProfile' + 'click @ui.changeQualityProfile': 'changeQualityProfile' + 'click @ui.createCustomRule': 'createCustomRule' + 'click @ui.changeCustomRule': 'changeCustomRule' + 'click @ui.changeManualRule': 'changeManualRule' + 'click @ui.deleteCustomRule': 'deleteRule' + + 'click .coding-rules-detail-parameter-name': 'toggleParameterDescription' + 'click .coding-rules-subcharacteristic': 'showDebtPopup' + + initialize: (options) -> + super options + + if @model.get 'params' + origParams = @model.get('params') + @model.set 'params', _.sortBy(origParams, 'key') + + _.map options.actives, (active) => + _.extend active, options.app.getQualityProfileByKey active.qProfile + qualityProfiles = new Backbone.Collection options.actives, + comparator: 'name' + @qualityProfilesView = new CodingRulesDetailQualityProfilesView + app: @options.app + collection: qualityProfiles + rule: @model + + unless @model.get 'isTemplate' + qualityProfileKey = @options.app.getQualityProfile() + + if qualityProfileKey + @contextProfile = qualityProfiles.findWhere qProfile: qualityProfileKey + unless @contextProfile + @contextProfile = new Backbone.Model + key: qualityProfileKey, name: @options.app.qualityProfileFilter.view.renderValue() + @contextQualityProfileView = new CodingRulesDetailQualityProfileView + app: @options.app + model: @contextProfile + rule: @model + qualityProfiles: qualityProfiles + + @listenTo @contextProfile, 'destroy', @hideContext + + onRender: -> + @$el.find('.open-modal').modal() + + if @model.get 'isTemplate' + @$(@contextRegion.el).hide() + + if _.isEmpty(@options.actives) + @$(@qualityProfilesRegion.el).hide() + else + @qualityProfilesRegion.show @qualityProfilesView + + @$(@customRulesRegion.el).show() + customRulesOriginal = @$(@customRulesRegion.el).html() + + @$(@customRulesRegion.el).html '' + + customRules = new Backbone.Collection() + jQuery.ajax + url: "#{baseUrl}/api/rules/search" + data: + template_key: @model.get 'key' + f: 'name,severity,params' + .done (r) => + customRules.add r.rules + + # Protect against element disappearing due to navigation + if @customRulesRegion + if customRules.isEmpty() and not @options.app.canWrite + @$(@customRulesRegion.el).hide() + else + @customRulesView = new CodingRulesDetailCustomRulesView + app: @options.app + collection: customRules + templateRule: @model + @$(@customRulesRegion.el).html customRulesOriginal + @customRulesListRegion.show @customRulesView + + else + @$(@customRulesRegion.el).hide() + @$(@qualityProfilesRegion.el).show() + @qualityProfilesRegion.show @qualityProfilesView + + if @options.app.getQualityProfile() and (@options.app.canWrite or @contextProfile.has('severity')) + @$(@contextRegion.el).show() + @contextRegion.show @contextQualityProfileView + else + @$(@contextRegion.el).hide() + + that = @ + jQuery.ajax + url: "#{baseUrl}/api/rules/tags" + .done (r) => + if @ui.tagInput.select2 + # Prevent synchronization issue with navigation + @ui.tagInput.select2 + tags: _.difference (_.difference r.tags, that.model.get 'tags'), that.model.get 'sysTags' + width: '300px' + + @ui.tagsEdit.hide() + + @ui.extendDescriptionForm.hide() + @ui.extendDescriptionSpinner.hide() + + + toggleParameterDescription: (e) -> + jQuery(e.currentTarget).next('.coding-rules-detail-parameter-description').toggle(); + + + showDebtPopup: (e) -> + e.stopPropagation() + jQuery('body').click() + popup = new CodingRulesDebtPopupView + model: @model + app: @options.app + triggerEl: jQuery(e.currentTarget) + popup.render() + false + + + hideContext: -> + @contextRegion.reset() + @$(@contextRegion.el).hide() + + + changeTags: -> + if @ui.tagsEdit.show + @ui.tagsEdit.show() + if @ui.tagsList.hide + @ui.tagsList.hide() + @tagsBuffer = @ui.tagInput.select2 'val' + key.setScope 'tags' + key 'escape', 'tags', => @cancelEdit() + + + cancelEdit: -> + key.unbind 'escape', 'tags' + if @ui.tagsList.show + @ui.tagsList.show() + if @ui.tagInput.select2 + console.log @tagsBuffer + @ui.tagInput.select2 'val', @tagsBuffer + @ui.tagInput.select2 'close' + if @ui.tagsEdit.hide + @ui.tagsEdit.hide() + + + editDone: -> + @ui.tagsEdit.html '' + tags = @ui.tagInput.val() + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/rules/update" + data: + key: @model.get 'key' + tags: tags + .done (r) => + @model.set 'tags', r.rule.tags + @cancelEdit() + .always => + @render() + + + showExtendDescriptionForm: -> + @ui.descriptionExtra.hide() + @ui.extendDescriptionForm.show() + key.setScope 'extraDesc' + key 'escape', 'extraDesc', => @hideExtendDescriptionForm() + @ui.extendDescriptionText.focus() + + + hideExtendDescriptionForm: -> + key.unbind 'escape', 'extraDesc' + @ui.descriptionExtra.show() + @ui.extendDescriptionForm.hide() + + + submitExtendDescription: -> + @ui.extendDescriptionForm.hide() + @ui.extendDescriptionSpinner.show() + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/rules/update" + dataType: 'json' + data: + key: @model.get 'key' + markdown_note: @ui.extendDescriptionText.val() + .done (r) => + @model.set + htmlNote: r.rule.htmlNote + mdNote: r.rule.mdNote + @render() + + + removeExtendedDescription: -> + confirmDialog + html: t 'coding_rules.remove_extended_description.confirm' + yesHandler: => + @ui.extendDescriptionText.val '' + @submitExtendDescription() + + + activateQualityProfile: -> + @options.app.codingRulesQualityProfileActivationView.model = null + @options.app.codingRulesQualityProfileActivationView.show() + + + activateContextQualityProfile: -> + @options.app.codingRulesQualityProfileActivationView.model = @contextProfile + @options.app.codingRulesQualityProfileActivationView.show() + + createCustomRule: -> + @options.app.codingRulesCustomRuleCreationView.templateRule = @model + @options.app.codingRulesCustomRuleCreationView.model = new Backbone.Model() + @options.app.codingRulesCustomRuleCreationView.show() + + + changeCustomRule: -> + @options.app.codingRulesCustomRuleCreationView.model = @model + @options.app.codingRulesCustomRuleCreationView.show() + + + changeManualRule: -> + @options.app.codingRulesManualRuleCreationView.model = @model + @options.app.codingRulesManualRuleCreationView.show() + + + deleteRule: -> + ruleType = if @model.has('templateKey') then 'custom' else 'manual' + confirmDialog + title: t 'delete' + html: tp "coding_rules.delete.#{ruleType}.confirm", @model.get('name') + yesHandler: => + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/rules/delete" + data: + key: @model.get 'key' + .done => + @options.app.fetchFirstPage() + .fail => + @options.app.showRule @model.get('key') + + + serializeData: -> + contextQualityProfile = @options.app.getQualityProfile() + repoKey = @model.get 'repo' + isManual = (@options.app.manualRepository().key == repoKey) + isCustom = (@model.has 'templateKey') + + qualityProfilesVisible = not isManual + if qualityProfilesVisible + if @model.get 'isTemplate' + qualityProfilesVisible = (not _.isEmpty(@options.actives)) + else + qualityProfilesVisible = (@options.app.canWrite or not _.isEmpty(@options.actives)) + + + _.extend super, + contextQualityProfile: contextQualityProfile + contextQualityProfileName: @options.app.qualityProfileFilter.view.renderValue() + qualityProfile: @contextProfile + language: @options.app.languages[@model.get 'lang'] + repository: _.find(@options.app.repositories, (repo) -> repo.key == repoKey).name + isManual: isManual + canWrite: @options.app.canWrite + isEditable: (@options.app.canWrite and (isManual or isCustom)) + qualityProfilesVisible: qualityProfilesVisible + subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar') + createdAt: moment(@model.get 'createdAt').toDate() + allTags: _.union @model.get('sysTags'), @model.get('tags') diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-facets-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-facets-view.coffee new file mode 100644 index 00000000000..7a209398fff --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-facets-view.coffee @@ -0,0 +1,53 @@ +define [ + 'backbone.marionette' + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesFacetsView extends Marionette.ItemView + template: Templates['coding-rules-facets'] + + + ui: + facets: '.navigator-facets-list-item' + options: '.facet' + + + events: + 'click @ui.options': 'selectOption' + + + initialize: -> + super() + that = @ + @options.collection.each (facet) -> + property = facet.get 'property' + facet.set 'property_message', t 'coding_rules.facets.' + property + facet.set 'limitReached', facet.get('values').length >= 10 + _.each(facet.get('values'), (value) -> + value.text = that.options.app.facetLabel(property, value.val) + ) + + selectOption: (e) -> + option = jQuery(e.currentTarget) + option.toggleClass 'active' + property = option.closest('.navigator-facets-list-item').data('property') + value = option.data('key') + @options.app.filterBarView.toggle(property, value) + @applyOptions() + + + applyOptions: -> + @options.app.fetchFirstPage() + + + restoreFromQuery: (params) -> + @ui.options.each -> + jQuery(@).removeClass('active') + @ui.facets.each -> + property = jQuery(@).data 'property' + if !!params[property] + _(params[property].split(',')).map (value) -> + jQuery('.navigator-facets-list-item[data-property="' + property + '"] .facet[data-key="' + value + '"]').addClass 'active' diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-empty-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-empty-view.coffee new file mode 100644 index 00000000000..a428e4cf256 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-empty-view.coffee @@ -0,0 +1,12 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesListEmptyView extends Marionette.ItemView + tagName: 'li' + className: 'navigator-results-no-results' + template: Templates['coding-rules-list-empty'] diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-item-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-item-view.coffee new file mode 100644 index 00000000000..6b46abada7e --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-item-view.coffee @@ -0,0 +1,31 @@ +define [ + 'backbone.marionette', + 'coding-rules-old/views/coding-rules-detail-view', + 'templates/coding-rules-old' +], ( + Marionette, + CodingRulesDetailView, + Templates +) -> + + class CodingRulesListItemView extends Marionette.ItemView + tagName: 'li' + template: Templates['coding-rules-list-item'] + activeClass: 'active' + + + events: -> + 'click': 'showDetail' + + + showDetail: -> + @options.listView.selectIssue @$el + @options.app.showRule @model.get('key') + + + serializeData: -> + tags = _.union @model.get('sysTags'), @model.get('tags') + _.extend super, + manualRuleLabel: t 'coding_rules.manual_rule' + allTags: tags + showDetails: (@model.get('status') != 'READY') || (_.isArray(tags) && tags.length > 0) diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-view.coffee new file mode 100644 index 00000000000..7669b57870c --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-list-view.coffee @@ -0,0 +1,93 @@ +define [ + 'backbone.marionette', + 'coding-rules-old/views/coding-rules-list-item-view', + 'coding-rules-old/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 + + + initialize: -> + openRule = (el) -> el.click() + @openRule = _.debounce openRule, 300 + key.setScope 'list' + + + onRender: -> + key 'up', 'list', (e) => + @selectPrev() + #e.stopPropagation() + key 'down', 'list', (e) => + @selectNext() + #e.stopPropagation() + + $scrollEl = jQuery('.navigator-results') + scrollEl = $scrollEl.get(0) + onScroll = => + if scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight + @options.app.fetchNextPage() + throttledScroll = _.throttle onScroll, 300 + $scrollEl.off('scroll').on 'scroll', throttledScroll + + + onClose: -> + @unbindEvents() + + + unbindEvents: -> + key.unbind 'up', 'list' + key.unbind 'down', 'list' + + + selectIssue: (el, open) -> + @$('.active').removeClass 'active' + el.addClass 'active' + ruleKey = el.find('[name]').attr('name') + rule = @collection.findWhere key: ruleKey + @selected = @collection.indexOf(rule) + @openRule el if open + + + selectFirst: -> + @selected = -1 + @selectNext() + + + selectCurrent: -> + @selected-- + @selectNext() + + + selectNext: -> + if @selected + 1 < @collection.length + @selected += 1 + child = @$el.children().eq(@selected) + container = jQuery('.navigator-results') + containerHeight = container.height() + bottom = child.position().top + child.outerHeight() + if bottom > containerHeight + container.scrollTop(container.scrollTop() - containerHeight + bottom) + @selectIssue child, true + + + selectPrev: -> + if @selected > 0 + @selected -= 1 + child = @$el.children().eq(@selected) + container = jQuery('.navigator-results') + top = child.position().top + if top < 0 + container.scrollTop(container.scrollTop() + top) + @selectIssue child, true diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-manual-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-manual-rule-creation-view.coffee new file mode 100644 index 00000000000..5d48f9cd6a2 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-manual-rule-creation-view.coffee @@ -0,0 +1,133 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesManualRuleCreationView extends Marionette.ItemView + template: Templates['coding-rules-manual-rule-creation'] + + + ui: + manualRuleCreationKey: '#coding-rules-manual-rule-creation-key' + manualRuleCreationName: '#coding-rules-manual-rule-creation-name' + manualRuleCreationHtmlDescription: '#coding-rules-manual-rule-creation-html-description' + manualRuleCreationSeverity: '#coding-rules-manual-rule-creation-severity' + manualRuleCreationStatus: '#coding-rules-manual-rule-creation-status' + manualRuleCreationParameters: '[name]' + manualRuleCreationCreate: '#coding-rules-manual-rule-creation-create' + manualRuleCreationReactivate: '#coding-rules-manual-rule-creation-reactivate' + modalFoot: '.modal-foot' + + + events: + 'input @ui.manualRuleCreationName': 'generateKey' + 'keydown @ui.manualRuleCreationName': 'generateKey' + 'keyup @ui.manualRuleCreationName': 'generateKey' + + 'input @ui.manualRuleCreationKey': 'flagKey' + 'keydown @ui.manualRuleCreationKey': 'flagKey' + 'keyup @ui.manualRuleCreationKey': 'flagKey' + + 'click #coding-rules-manual-rule-creation-cancel': 'hide' + 'click @ui.manualRuleCreationCreate': 'create' + 'click @ui.manualRuleCreationReactivate': 'reactivate' + + + generateKey: -> + unless @keyModifiedByUser + if @ui.manualRuleCreationKey + generatedKey = @ui.manualRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_') + @ui.manualRuleCreationKey.val generatedKey + + flagKey: -> + @keyModifiedByUser = true + # Cannot use @ui.manualRuleCreationReactivate.hide() directly since it was not there at initial render + jQuery(@ui.manualRuleCreationReactivate.selector).hide() + + + create: -> + action = 'create' + if @model and @model.has 'key' + action = 'update' + + postData = + name: @ui.manualRuleCreationName.val() + markdown_description: @ui.manualRuleCreationHtmlDescription.val() + + if @model && @model.has 'key' + postData.key = @model.get 'key' + else + postData.manual_key = @ui.manualRuleCreationKey.val() + postData.prevent_reactivation = true + + @sendRequest(action, postData) + + + reactivate: -> + postData = + name: @existingRule.name + markdown_description: @existingRule.mdDesc + manual_key: @ui.manualRuleCreationKey.val() + prevent_reactivation: false + + @sendRequest('create', postData) + + + sendRequest: (action, postData) -> + @$('.modal-error').hide() + @$('.modal-warning').hide() + + origFooter = @ui.modalFoot.html() + @ui.modalFoot.html '' + + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/rules/" + action + data: postData + error: () -> + .done (r) => + @options.app.showRule r.rule.key + @hide() + .fail (jqXHR, textStatus, errorThrown) => + if jqXHR.status == 409 + @existingRule = jqXHR.responseJSON.rule + @$('.modal-warning').show() + @ui.modalFoot.html Templates['coding-rules-manual-rule-reactivation'](@) + else + jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown) + @ui.modalFoot.html origFooter + + + onRender: -> + @$el.dialog + dialogClass: 'no-close', + width: '600px', + draggable: false, + autoOpen: false, + modal: true, + minHeight: 50, + resizable: false, + title: null + + @keyModifiedByUser = false + + format = (state) -> + return state.text unless state.id + " #{state.text}" + + + show: -> + @render() + @$el.dialog 'open' + + + hide: -> + @$el.dialog 'close' + + + serializeData: -> + _.extend super, + change: @model && @model.has 'key' diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-parameter-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-parameter-popup-view.coffee new file mode 100644 index 00000000000..cdee87966e5 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-parameter-popup-view.coffee @@ -0,0 +1,15 @@ +define [ + 'backbone.marionette' + 'templates/coding-rules-old' + 'common/popup' +], ( + Marionette + Templates + Popup +) -> + + $ = jQuery + + + class CodingRulesParameterPopupView extends Popup + template: Templates['coding-rules-parameter-popup'] diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-quality-profile-activation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-quality-profile-activation-view.coffee new file mode 100644 index 00000000000..2d7f00aa7db --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/coding-rules-quality-profile-activation-view.coffee @@ -0,0 +1,124 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesQualityProfileActivationView extends Marionette.ItemView + className: 'coding-rules-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' + qualityProfileParameters: '[name]' + + + events: + 'click #coding-rules-quality-profile-activation-cancel': 'hide' + 'click @ui.qualityProfileActivate': 'activate' + + + activate: -> + profileKey = @ui.qualityProfileSelect.val() + params = @ui.qualityProfileParameters.map(-> + key: jQuery(@).prop('name'), value: jQuery(@).val() || jQuery(@).prop('placeholder') || '').get() + + paramsHash = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';') + + if @model + profileKey = @model.get('qProfile') + unless profileKey + profileKey = @model.get('key') + severity = @ui.qualityProfileSeverity.val() + + origFooter = @$('.modal-foot').html() + @$('.modal-foot').html '' + + ruleKey = @rule.get('key') + jQuery.ajax + type: 'POST' + url: "#{baseUrl}/api/qualityprofiles/activate_rule" + data: + profile_key: profileKey + rule_key: ruleKey + severity: severity + params: paramsHash + .done => + @options.app.showRule ruleKey + @hide() + .fail => + @$('.modal-foot').html origFooter + + + 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 + " #{state.text}" + + severity = (@model && @model.get 'severity') || @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: (lang) -> + activeQualityProfiles = @options.app.detailView.qualityProfilesView.collection + inactiveProfiles = _.reject @options.app.qualityProfiles, (profile) => + activeQualityProfiles.findWhere key: profile.key + _.filter inactiveProfiles, (profile) => + profile.lang == lang + + + serializeData: -> + params = @rule.get 'params' + if @model + modelParams = @model.get 'params' + if modelParams + params = params.map (p) -> + parentParam = _.findWhere(modelParams, key: p.key) + if parentParam + _.extend p, value: _.findWhere(modelParams, key: p.key).value + else + p + + availableProfiles = @getAvailableQualityProfiles(@rule.get 'lang') + + _.extend super, + rule: @rule.toJSON() + change: @model && @model.has 'severity' + params: params + qualityProfiles: availableProfiles + severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'] + saveEnabled: not _.isEmpty(availableProfiles) or (@model and @model.get('qProfile')) + isCustomRule: (@model and @model.has('templateKey')) or @rule.has 'templateKey' diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filter-bar-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filter-bar-view.coffee new file mode 100644 index 00000000000..edd69fb4d19 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filter-bar-view.coffee @@ -0,0 +1,97 @@ +define [ + 'navigator/filters/filter-bar', + 'navigator/filters/base-filters', + 'navigator/filters/favorite-filters', + 'navigator/filters/more-criteria-filters', + 'navigator/filters/read-only-filters', + 'templates/coding-rules-old' +], ( + FilterBarView, + BaseFilters, + FavoriteFiltersModule, + MoreCriteriaFilters, + ReadOnlyFilterView, + Templates +) -> + + class CodingRulesFilterBarView extends FilterBarView + template: Templates['coding-rules-filter-bar'] + + collectionEvents: + 'change:enabled': 'changeEnabled' + + + events: + 'click .navigator-filter-submit': 'search' + + + onRender: -> + @selectFirst() + + + 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: -> + readOnlyFilters = @collection.where(type: ReadOnlyFilterView) + disabledFilters = _.difference(@collection.where(enabled: false), readOnlyFilters) + 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') in [MoreCriteriaFilters.MoreCriteriaFilterView, ReadOnlyFilterView] + + 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: -> + @$('.navigator-filter-submit').blur() + @options.app.state.set + query: this.options.app.getQuery(), + search: true + @options.app.fetchFirstPage() + + + fetchNextPage: -> + @options.app.fetchNextPage() + + + restoreFromWsQuery: (query) -> + params = _.map(query, (value, key) -> + 'key': key + 'value': value + ) + @restoreFromQuery params + + + toggle: (property, value) -> + filter = @collection.findWhere(property: property) + unless filter.view.isActive() + @moreCriteriaFilter.view.detailsView.enableByProperty(property) + choice = filter.view.choices.get(value) + choice.set 'checked', !choice.get('checked') + filter.view.detailsView.updateValue() + filter.view.detailsView.updateLists() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/activation-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/activation-filter-view.coffee new file mode 100644 index 00000000000..e6d33997d7e --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/activation-filter-view.coffee @@ -0,0 +1,32 @@ +define [ + 'coding-rules-old/views/filters/profile-dependent-filter-view' +], ( + ProfileDependentFilterView +) -> + + class ActivationFilterView extends ProfileDependentFilterView + tooltip: 'coding_rules.filters.activation.help' + + + makeActive: -> + super + filterValue = @model.get 'value' + if !filterValue or filterValue.length == 0 + @choices.each (model) -> model.set 'checked', model.id == 'true' + @model.set 'value', ['true'] + @detailsView.updateLists() + + + + showDetails: -> + super unless @$el.is '.navigator-filter-inactive' + + + restore: (value) -> + value = value.split(',') if _.isString(value) + if @choices && value.length > 0 + @choices.each (model) -> model.set 'checked', value.indexOf(model.id) >= 0 + @model.set value: value, enabled: true + @onChangeQualityProfile() + else + @clear() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/active-severities-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/active-severities-filter-view.coffee new file mode 100644 index 00000000000..5c07e2333d9 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/active-severities-filter-view.coffee @@ -0,0 +1,9 @@ + +define [ + 'coding-rules-old/views/filters/profile-dependent-filter-view' +], ( + ProfileDependentFilterView +) -> + + class ActiveSeveritiesFilterView extends ProfileDependentFilterView + tooltip: 'coding_rules.filters.active_severity.inactive' diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/characteristic-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/characteristic-filter-view.coffee new file mode 100644 index 00000000000..efa29a733ff --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/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/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/inheritance-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/inheritance-filter-view.coffee new file mode 100644 index 00000000000..0a201375cf1 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/inheritance-filter-view.coffee @@ -0,0 +1,23 @@ +define [ + 'coding-rules-old/views/filters/profile-dependent-filter-view' +], ( + ProfileDependentFilterView +) -> + + class InheritanceFilterView extends ProfileDependentFilterView + tooltip: 'coding_rules.filters.inheritance.inactive' + + onChangeQualityProfile: -> + qualityProfileKey = @qualityProfileFilter.get 'value' + if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1 + qualityProfile = @options.app.getQualityProfileByKey qualityProfileKey[0] + if qualityProfile.parentKey + parentQualityProfile = @options.app.getQualityProfile qualityProfile.parentKey + if parentQualityProfile + @makeActive() + else + @makeInactive() + else + @makeInactive() + else + @makeInactive() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/language-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/language-filter-view.coffee new file mode 100644 index 00000000000..3e5ea0a5cdb --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/language-filter-view.coffee @@ -0,0 +1,45 @@ +define [ + 'navigator/filters/choice-filters', + 'templates/coding-rules-old' +], ( + ChoiceFilters, + Templates +) -> + + class LanguageFilterView extends ChoiceFilters.ChoiceFilterView + + modelEvents: + 'change:value': 'onChangeValue' + 'change:enabled': 'focus', + + + initialize: -> + super + @choices.comparator = 'text' + @choices.sort() + @app = @model.get 'app' + @listenTo @app.qualityProfileFilter, 'change:value', @onChangeProfile + @selectedFromProfile = false + + onChangeProfile: -> + profiles = @app.qualityProfileFilter.get 'value' + if _.isArray(profiles) && profiles.length > 0 + profile = _.findWhere @app.qualityProfiles, key: profiles[0] + @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property') + @choices.each (item) -> item.set 'checked', item.id == profile.lang + @refreshValues() + @selectedFromProfile = true + else if @selectedFromProfile + @choices.each (item) -> item.set 'checked', false + @refreshValues() + + onChangeValue: -> + @selectedFromProfile = false + @renderBase() + + + refreshValues: -> + @detailsView.updateValue() + @detailsView.updateLists() + @render() + @hideDetails() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/profile-dependent-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/profile-dependent-filter-view.coffee new file mode 100644 index 00000000000..5afad402b92 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/profile-dependent-filter-view.coffee @@ -0,0 +1,57 @@ +define [ + 'navigator/filters/choice-filters' +], ( + ChoiceFilters +) -> + + class ProfileDependentFilterView extends ChoiceFilters.ChoiceFilterView + tooltip: 'coding_rules.filters.activation.help' + + initialize: -> + super + @qualityProfileFilter = @model.get 'qualityProfileFilter' + @listenTo @qualityProfileFilter, 'change:value', @onChangeQualityProfile + @onChangeQualityProfile() + + + onChangeQualityProfile: -> + qualityProfileKey = @qualityProfileFilter.get 'value' + if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1 + @makeActive() + else + @makeInactive() + + + makeActive: -> + @model.set inactive: false, title: '' + @model.trigger 'change:enabled' + @$el.removeClass('navigator-filter-inactive').prop 'title', '' + @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property') + @hideDetails() + + + 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 + @choices.each (item) -> + item.set 'checked', false + _.each value, (v) => + cModel = @choices.findWhere id: v + cModel.set 'checked', true + @onChangeQualityProfile() + else + @clear() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/quality-profile-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/quality-profile-filter-view.coffee new file mode 100644 index 00000000000..3dde4d0f0be --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/quality-profile-filter-view.coffee @@ -0,0 +1,61 @@ +define [ + 'navigator/filters/choice-filters', + 'templates/coding-rules-old' +], ( + ChoiceFilters, + Templates +) -> + + class QualityProfileDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView + itemTemplate: Templates['coding-rules-profile-filter-detail'] + + + class QualityProfileFilterView extends ChoiceFilters.ChoiceFilterView + + initialize: -> + super + detailsView: QualityProfileDetailFilterView + + @app = @model.get 'app' + + @allProfiles = @model.get 'choices' + @updateChoices @allProfiles + + @listenTo @app.languageFilter, 'change:value', @onChangeLanguage + @onChangeLanguage() + + + onChangeLanguage: -> + languages = @app.languageFilter.get 'value' + if _.isArray(languages) && languages.length > 0 + @filterLanguages(languages) + else + @updateChoices(@allProfiles) + + filterLanguages: (languages) -> + languageProfiles = _.filter( @allProfiles, (prof) -> languages.indexOf(prof.lang) >= 0 ) + @updateChoices(languageProfiles) + + + updateChoices: (collection) -> + languages = @app.languages + currentValue = @model.get('value') + @choices = new Backbone.Collection( _.map collection, (item, index) -> + new Backbone.Model + id: item.key + text: item.name + checked: false + index: index + language: languages[item.lang] + comparator: 'index' + ) + if currentValue + @restore(currentValue) + @render() + + render: -> + super + if @model.get 'value' + @$el.addClass('navigator-filter-context') + else + @$el.removeClass('navigator-filter-context') diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/query-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/query-filter-view.coffee new file mode 100644 index 00000000000..fa57264bd7a --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/query-filter-view.coffee @@ -0,0 +1,81 @@ +define [ + 'backbone', + 'backbone.marionette', + 'navigator/filters/base-filters', + 'navigator/filters/string-filters', + 'navigator/filters/choice-filters', + 'templates/coding-rules-old', + 'common/handlebars-extensions' +], ( + Backbone, + Marionette, + BaseFilters, + StringFilterView, + ChoiceFilters, + Templates +) -> + + class QueryFilterView extends StringFilterView + template: Templates['coding-rules-query-filter'] + className: 'navigator-filter navigator-filter-query' + + events: + 'keypress input': 'checkSubmit' + 'change input': 'change' + 'click': 'focus' + 'blur': 'blur' + + + change: (e) -> + @model.set 'value', $j(e.target).val() + @options.app.codingRules.sorting = sort: '', asc: '' + + + clear: -> + super + @focus() + + + focus: -> + @$(':input').focus(); + + + blur: -> + @$(':input').blur(); + + + serializeData: -> + return _.extend({}, @model.toJSON(), + value: this.model.get('value') || '' + ) + + + initialize: -> + super detailsView: null + @model.set('size', 25) unless @model.get 'size' + + + checkSubmit: (e) -> + if (e.which == 13) + e.preventDefault() + @change(e) + @blur() + @options.app.filterBarView.$('.navigator-filter-submit').focus() + @options.app.filterBarView.$('.navigator-filter-submit').click() + + + renderInput: -> + # Done in template + + + toggleDetails: -> + # NOP + + + isDefaultValue: -> + true + + + renderBase: -> + super + @$el.prop('title', ''); diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/repository-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/repository-filter-view.coffee new file mode 100644 index 00000000000..82dc8e675dd --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/repository-filter-view.coffee @@ -0,0 +1,55 @@ +define [ + 'navigator/filters/choice-filters', + 'templates/coding-rules-old' +], ( + ChoiceFilters, + Templates +) -> + + class RepositoryDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView + itemTemplate: Templates['coding-rules-repository-detail'] + + + class RepositoryFilterView extends ChoiceFilters.ChoiceFilterView + + initialize: -> + super + detailsView: RepositoryDetailFilterView + + @app = @model.get 'app' + + @allRepositories = @model.get 'choices' + @updateChoices @allRepositories + + @listenTo @app.languageFilter, 'change:value', @onChangeLanguage + @onChangeLanguage() + + + onChangeLanguage: -> + languages = @app.languageFilter.get 'value' + if _.isArray(languages) && languages.length > 0 + @filterLanguages(languages) + else + @updateChoices(@allRepositories) + + filterLanguages: (languages) -> + languageRepositories = _.filter( @allRepositories, (repo) -> languages.indexOf(repo.language) >= 0 ) + @updateChoices(languageRepositories) + + + updateChoices: (collection) -> + languages = @app.languages + currentValue = @model.get('value') + @choices = new Backbone.Collection( _.map collection, (item, index) -> + new Backbone.Model + id: item.key + text: item.name + checked: false + index: index + language: languages[item.language] + comparator: (item) -> + [item.get('text'), item.get('language')] + ) + if currentValue + @restore(currentValue) + @render() diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/tag-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/tag-filter-view.coffee new file mode 100644 index 00000000000..01366e7f2e4 --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/filters/tag-filter-view.coffee @@ -0,0 +1,38 @@ +define [ + 'navigator/filters/choice-filters' +], ( + ChoiceFilters +) -> + + class TagFilterView extends ChoiceFilters.ChoiceFilterView + + initialize: -> + super() + @loadTags() + # TODO Register an event handler to reload tags when they are modified on a rule + + + loadTags: -> + tagsXHR = jQuery.ajax + url: "#{baseUrl}/api/rules/tags" + async: false + + jQuery.when(tagsXHR).done (r) => + @choices = new Backbone.Collection( + _.map(r.tags, (tag) -> + new Backbone.Model + id: tag + text: tag + ), + comparator: 'text') + + if @tagToRestore + @restore(@tagToRestore) + @tagToRestore = null + @render() + + restore: (value) -> + unless @choices.isEmpty() + super(value) + else + @tagToRestore = value diff --git a/server/sonar-web/src/main/coffee/coding-rules-old/views/header-view.coffee b/server/sonar-web/src/main/coffee/coding-rules-old/views/header-view.coffee new file mode 100644 index 00000000000..13a71b5e75d --- /dev/null +++ b/server/sonar-web/src/main/coffee/coding-rules-old/views/header-view.coffee @@ -0,0 +1,28 @@ +define [ + 'backbone.marionette', + 'templates/coding-rules-old' +], ( + Marionette, + Templates +) -> + + class CodingRulesHeaderView extends Marionette.ItemView + template: Templates['coding-rules-header'] + + + events: + 'click #coding-rules-new-search': 'newSearch' + 'click #coding-rules-create-rule': 'createRule' + + + newSearch: -> + @options.app.router.emptyQuery() + + + createRule: -> + @options.app.createManualRule() + + + serializeData: -> + _.extend super, + 'canWrite': @options.app.canWrite diff --git a/server/sonar-web/src/main/coffee/coding-rules/app.coffee b/server/sonar-web/src/main/coffee/coding-rules/app.coffee deleted file mode 100644 index 953c0091080..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/app.coffee +++ /dev/null @@ -1,521 +0,0 @@ -requirejs.config - baseUrl: "#{baseUrl}/js" - - paths: - 'backbone': 'third-party/backbone' - 'backbone.marionette': 'third-party/backbone.marionette' - 'handlebars': 'third-party/handlebars' - - 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-detail-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', - 'coding-rules/views/coding-rules-facets-view', - 'coding-rules/views/coding-rules-custom-rule-creation-view', - 'coding-rules/views/coding-rules-manual-rule-creation-view', - - # filters - 'navigator/filters/base-filters', - 'navigator/filters/choice-filters', - 'navigator/filters/string-filters', - 'navigator/filters/date-filter-view', - 'navigator/filters/read-only-filters', - 'coding-rules/views/filters/query-filter-view', - 'coding-rules/views/filters/quality-profile-filter-view', - 'coding-rules/views/filters/inheritance-filter-view', - 'coding-rules/views/filters/active-severities-filter-view', - 'coding-rules/views/filters/activation-filter-view', - 'coding-rules/views/filters/characteristic-filter-view', - 'coding-rules/views/filters/repository-filter-view', - 'coding-rules/views/filters/tag-filter-view', - 'coding-rules/views/filters/language-filter-view', - - 'common/handlebars-extensions' -], ( - Backbone, Marionette, - - CodingRulesLayout, - CodingRulesRouter, - - # views - CodingRulesHeaderView, - CodingRulesActionsView, - CodingRulesFilterBarView, - CodingRulesListView, - CodingRulesDetailView, - CodingRulesBulkChangeView, - CodingRulesQualityProfileActivationView, - CodingRulesBulkChangeDropdownView, - CodingRulesFacetsView, - CodingRulesCustomRuleCreationView, - CodingRulesManualRuleCreationView, - - # filters - BaseFilters, - ChoiceFilters, - StringFilterView, - DateFilterView, - ReadOnlyFilterView, - QueryFilterView, - QualityProfileFilterView, - InheritanceFilterView, - ActiveSeveritiesFilterView, - ActivationFilterView, - CharacteristicFilterView, - RepositoryFilterView, - TagFilterView, - LanguageFilterView -) -> - - # 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 '. ' - else - text = t 'default_error_message' - 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 = (params) -> - sort = _.findWhere(params, key: 'sort') - asc = _.findWhere(params, key: 'asc') - - if (sort && asc) - @codingRules.sorting = - sort: sort.value - asc: asc.value =='true' - - - App.restoreDefaultSorting = -> - params = [] - params.push(key: 'sort', value: 'createdAt') - params.push(key: 'asc', value: false) - @restoreSorting params - - - App.storeQuery = (query, sorting) -> - if sorting && sorting.sort - _.extend query, - s: 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 { p: @pageIndex, ps: 25, facets: firstPage }, query - - if @codingRules.sorting && @codingRules.sorting.sort - _.extend fetchQuery, - s: @codingRules.sorting.sort, - asc: @codingRules.sorting.asc - - @storeQuery query, @codingRules.sorting - - # Optimize requested fields - _.extend fetchQuery, f: 'name,lang,status,tags,sysTags' - - if @codingRulesListView - scrollOffset = jQuery('.navigator-results')[0].scrollTop - else - scrollOffset = 0 - - @layout.showSpinner 'resultsRegion' - @layout.showSpinner 'facetsRegion' if firstPage - - - jQuery.ajax - url: "#{baseUrl}/api/rules/search" - data: fetchQuery - .done (r) => - _.map(r.rules, (rule) -> - rule.language = App.languages[rule.lang] - ) - - @codingRules.paging = - total: r.total - pageIndex: r.p - pageSize: r.ps - pages: 1 + (r.total / r.ps) - - if @codingRulesListView - @codingRulesListView.close() - - if firstPage - @codingRules.reset r.rules - @codingRulesListView = new CodingRulesListView - app: @ - collection: @codingRules - else - @codingRulesListView.unbindEvents() - @codingRules.add r.rules - - @layout.resultsRegion.show @codingRulesListView - - - if @codingRules.isEmpty() - @layout.detailsRegion.reset() - else if firstPage - @codingRulesListView.selectFirst() - else - @codingRulesListView.selectCurrent() - - if firstPage - @codingRulesFacetsView = new CodingRulesFacetsView - app: @ - collection: new Backbone.Collection r.facets, comparator: 'property' - @layout.facetsRegion.show @codingRulesFacetsView - @filterBarView.restoreFromWsQuery query - @codingRulesFacetsView.restoreFromQuery query - else - jQuery('.navigator-results')[0].scrollTop = scrollOffset - - @layout.onResize() - - - - App.facetLabel = (property, value) -> - return value unless App.facetPropertyToLabels[property] - App.facetPropertyToLabels[property](value) - - - 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 - - - App.getQualityProfilesForLanguage = (language_key) -> - _.filter App.qualityProfiles, (p) => p.lang == language_key - - App.getQualityProfileByKey = (profile_key) -> - _.findWhere App.qualityProfiles, key: profile_key - - - App.getSubcharacteristicName = (name) -> - (App.characteristics[name] || '').replace ': ', ' > ' - - - App.showRule = (ruleKey) -> - App.layout.showSpinner 'detailsRegion' - jQuery.ajax - url: "#{baseUrl}/api/rules/show" - data: - key: ruleKey - actives: true - .done (r) => - rule = new Backbone.Model(r.rule) - App.codingRulesQualityProfileActivationView.rule = rule - App.detailView = new CodingRulesDetailView - app: App - model: rule - actives: r.actives - App.layout.detailsRegion.show App.detailView - - - App.manualRepository = -> - key: 'manual' - name: 'Manual Rules' - language: 'none' - - - App.createManualRule = -> - App.codingRulesManualRuleCreationView.model = new Backbone.Model() - App.codingRulesManualRuleCreationView.show() - - - # Construct layout - App.addInitializer -> - @layout = new CodingRulesLayout app: @ - jQuery('#content').append @layout.render().el - @layout.onResize() - - - # Construct header - App.addInitializer -> - @codingRulesHeaderView = new CodingRulesHeaderView app: @ - @layout.headerRegion.show @codingRulesHeaderView - - - # Define coding rules - App.addInitializer -> - @codingRules = new Backbone.Collection - @restoreDefaultSorting() - - - # 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: @ - - - # Construct custom rule creation view - App.addInitializer -> - @codingRulesCustomRuleCreationView = new CodingRulesCustomRuleCreationView app: @ - - - # Construct custom rule creation view - App.addInitializer -> - @codingRulesManualRuleCreationView = new CodingRulesManualRuleCreationView app: @ - - # Define filters - App.addInitializer -> - @filters = new BaseFilters.Filters - - @queryFilter = new BaseFilters.Filter - property: 'q' - type: QueryFilterView - size: 50 - @filters.add @queryFilter - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.severity' - property: 'severities' - type: ChoiceFilters.ChoiceFilterView - optional: true - 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: TagFilterView - optional: true - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.characteristic' - property: 'debt_characteristics' - type: CharacteristicFilterView - choices: @characteristics - multiple: false - optional: true - - @qualityProfileFilter = new BaseFilters.Filter - name: t 'coding_rules.filters.quality_profile' - property: 'qprofile' - type: QualityProfileFilterView - app: @ - choices: @qualityProfiles - multiple: false - @filters.add @qualityProfileFilter - - @activationFilter = new BaseFilters.Filter - name: t 'coding_rules.filters.activation' - property: 'activation' - type: ActivationFilterView - enabled: false - optional: true - multiple: false - qualityProfileFilter: @qualityProfileFilter - choices: - true: t 'coding_rules.filters.activation.active' - false: t 'coding_rules.filters.activation.inactive' - @filters.add @activationFilter - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.active_severity' - property: 'active_severities' - type: ActiveSeveritiesFilterView - enabled: false - optional: true - qualityProfileFilter: @qualityProfileFilter - 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' - - @languageFilter = new BaseFilters.Filter - name: t 'coding_rules.filters.language' - property: 'languages' - type: LanguageFilterView - app: @ - choices: @languages - optional: true - @filters.add @languageFilter - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.availableSince' - property: 'available_since' - type: DateFilterView - 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: - 'NONE': t 'coding_rules.filters.inheritance.not_inherited' - 'INHERITED': t 'coding_rules.filters.inheritance.inherited' - 'OVERRIDES': t 'coding_rules.filters.inheritance.overriden' - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.repository' - property: 'repositories' - type: RepositoryFilterView - enabled: false - optional: true - app: @ - choices: @repositories - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.status' - property: 'statuses' - type: ChoiceFilters.ChoiceFilterView - enabled: false - optional: true - choices: @statuses - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.template' - property: 'is_template' - type: ChoiceFilters.ChoiceFilterView - optional: true - multiple: false - choices: - 'true': t 'coding_rules.filters.template.is_template' - 'false': t 'coding_rules.filters.template.is_not_template' - - @filters.add new BaseFilters.Filter - name: t 'coding_rules.filters.key' - property: 'rule_key' - type: ReadOnlyFilterView - enabled: false - optional: true - - - @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/rules/app" - .done (r) -> - App.appState = new Backbone.Model - App.state = new Backbone.Model - App.canWrite = r.canWrite - App.qualityProfiles = _.sortBy r.qualityprofiles, ['name', 'lang'] - App.languages = _.extend r.languages, none: 'None' - _.map App.qualityProfiles, (profile) -> - profile.language = App.languages[profile.lang] - App.repositories = r.repositories - App.repositories.push App.manualRepository() - App.statuses = r.statuses - App.characteristics = r.characteristics - - App.facetPropertyToLabels = - 'languages': (value) -> App.languages[value] - 'repositories': (value) -> - repo = _.findWhere(App.repositories, key: value) - other_repo_with_same_name = _.find(App.repositories, (repos) -> repos.name == repo.name && repos.key != repo.key) - if other_repo_with_same_name - App.languages[repo.language] + ' ' + repo.name - else - repo.name - - # Message bundles - l10nXHR = window.requestMessages() - - jQuery.when(l10nXHR, appXHR).done -> - # Remove the initial spinner - jQuery('#coding-rules-page-loader').remove() - - # Start the application - App.start() diff --git a/server/sonar-web/src/main/coffee/coding-rules/layout.coffee b/server/sonar-web/src/main/coffee/coding-rules/layout.coffee deleted file mode 100644 index 8008248f670..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/layout.coffee +++ /dev/null @@ -1,90 +0,0 @@ -define [ - 'backbone.marionette', - 'templates/coding-rules' -], ( - Marionette, - Templates -) -> - - class AppLayout extends Marionette.Layout - className: 'navigator coding-rules-navigator' - template: Templates['coding-rules-layout'] - storageKey: 'codingRulesResultsWidth' - - - regions: - headerRegion: '.navigator-header' - actionsRegion: '.navigator-actions' - resultsRegion: '.navigator-results' - detailsRegion: '.navigator-details' - filtersRegion: '.navigator-filters' - facetsRegion: '.navigator-facets' - - - ui: - side: '.navigator-side' - results: '.navigator-results' - details: '.navigator-details' - resizer: '.navigator-resizer' - - - initialize: -> - jQuery(window).on 'resize', => @onResize() - - @isResize = false - jQuery('body').on 'mousemove', (e) => @processResize(e) - jQuery('body').on 'mouseup', => @stopResize() - - - onRender: -> - @ui.resizer.on 'mousedown', (e) => @startResize(e) - - resultsWidth = localStorage.getItem @storageKey - if resultsWidth - @$(@resultsRegion.el).width +resultsWidth - @ui.side.width +resultsWidth + 20 - - - onResize: -> - footerEl = jQuery('#footer') - footerHeight = footerEl.outerHeight true - - resultsEl = @ui.results - resultsHeight = jQuery(window).height() - resultsEl.offset().top - - parseInt(resultsEl.css('margin-bottom'), 10) - footerHeight - resultsEl.height resultsHeight - - detailsEl = @ui.details - detailsWidth = jQuery(window).width() - detailsEl.offset().left - - parseInt(detailsEl.css('margin-right'), 10) - detailsHeight = jQuery(window).height() - detailsEl.offset().top - - parseInt(detailsEl.css('margin-bottom'), 10) - footerHeight - detailsEl.width(detailsWidth).height detailsHeight - - - showSpinner: (region) -> - @[region].show new Marionette.ItemView - template: _.template('') - - - startResize: (e) -> - @isResize = true - @originalWidth = @ui.results.width() - @x = e.clientX - jQuery('html').attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false) - - - processResize: (e) -> - if @isResize - delta = e.clientX - @x - @$(@resultsRegion.el).width @originalWidth + delta - @ui.side.width @originalWidth + 20 + delta - localStorage.setItem @storageKey, @ui.results.width() - @onResize() - - - stopResize: -> - if @isResize - jQuery('html').attr('unselectable', 'off').css('user-select', 'text').off('selectstart') - @isResize = false - true diff --git a/server/sonar-web/src/main/coffee/coding-rules/mockjax.coffee b/server/sonar-web/src/main/coffee/coding-rules/mockjax.coffee deleted file mode 100644 index 30f37ba626b..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/mockjax.coffee +++ /dev/null @@ -1,364 +0,0 @@ -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' - 'are_you_sure': 'Are you sure?' - '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.activate_in_all_quality_profiles': 'Activate In All {0} Profiles' - '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.deactivate_in_all_quality_profiles': 'Deactivate In All {0} Profiles' - 'coding_rules.found': 'Found' - 'coding_rules.inherits': '"{0}" inherits "{1}"' - 'coding_rules.key': 'Key:' - 'coding_rules.new_search': 'New Search' - 'coding_rules.no_results': 'No Coding Rules' - 'coding_rules.no_tags': 'No tags' - '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.permalink': 'Permalink' - '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' - facets: [ - { - name: 'Languages' - property: 'languages' - values: [ - { key: 'java', text: 'Java', stat: 45 } - { key: 'javascript', text: 'JavaScript', stat: 21 } - ] - } - { - name: 'Tags' - property: 'tags' - values: [ - { key: 'brain-overload', text: 'brain-overload', stat: 8 } - { key: 'bug', text: 'bug', stat: 7 } - { key: 'comment', text: 'comment', stat: 7 } - { key: 'convention', text: 'convention', stat: 6 } - { key: 'error-handling', text: 'error-handling', stat: 5 } - ] - } - { - name: 'Repositories' - property: 'repositories' - values: [ - { key: 'squid', text: 'SonarQube', stat: 57 } - { key: 'pmd', text: 'PMD', stat: 17 } - ] - } - ] - - - - - # 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' - 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' } - { key: 'xpath', type: 'TEXT', description: 'XPath, the XML Path Language, is a query language for selecting nodes from an XML document. In addition, XPath may be used to compute values (e.g., strings, numbers, or Boolean values) from the content of an XML document. XPath was defined by the World Wide Web Consortium (W3C).' } - ] - description: ''' -

- According to the Java Language Specification: -

- -
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.
-            
- -

The following code snippet illustrates this rule:

- -
public int getVector()[] { /* ... */ }    // Non-Compliant
-
-            public int[] getVector() { /* ... */ }    // Compliant
-
-            public int[] getMatrix()[] { /* ... */ }  // Non-Compliant
-
-            public int[][] getMatrix() { /* ... */ }  // Compliant
-            
''' - extra: '''This note is here only for test purposes.''' - extraRaw: '''This note is here *only for test purposes*.''' - - qualityProfiles: [ - { - name: 'SonarWay' - key: 'sonarway' - severity: 'MINOR' - parameters: [ - { key: 'someParameter', value: 8 } - { key: 'xpath', value: '/child::html/child::body/child::*/child::span[attribute::class]' } - ] - }, - { - name: 'Quality Profile 1' - key: 'qualityprofile1' - severity: 'MAJOR' - parameters: [ - { key: 'someParameter', value: 6 } - { key: 'xpath', value: '/html/body/*/span[@class]' } - ] - inherits: 'sonarway' - } - ] - - - - # POST /api/codingrules/extend_description - jQuery.mockjax - url: "#{baseUrl}/api/codingrules/extend_description" - responseText: JSON.stringify - extra: '''This note is here only for test purposes.''' - 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: '''

This note is here only for test purposes.

''' - 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/server/sonar-web/src/main/coffee/coding-rules/router.coffee b/server/sonar-web/src/main/coffee/coding-rules/router.coffee deleted file mode 100644 index fe49b73dbbd..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/router.coffee +++ /dev/null @@ -1,39 +0,0 @@ -define [ - 'backbone', -], ( - Backbone, -) -> - - class AppRouter extends Backbone.Router - - routes: - '': 'emptyQuery' - ':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: -> - @app.restoreDefaultSorting() - @index('') - - - index: (query) -> - params = this.parseQuery(query) - @loadResults(params) - - - loadResults: (params) -> - @app.filterBarView.restoreFromQuery(params) - if @app.codingRulesFacetsView - @app.codingRulesFacetsView.restoreFromQuery(params) - @app.restoreSorting(params) - @app.fetchFirstPage() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/actions-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/actions-view.coffee deleted file mode 100644 index b5f13553de5..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/actions-view.coffee +++ /dev/null @@ -1,64 +0,0 @@ -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 - while not @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, - canWrite: @options.app.canWrite - paging: @collection.paging - sorting: @collection.sorting diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee deleted file mode 100644 index 27552173ff9..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-dropdown-view.coffee +++ /dev/null @@ -1,55 +0,0 @@ -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' - @options.app.codingRulesBulkChangeView.show action, param - - - onRender: -> - jQuery('body').append @el - jQuery('body').off('click.bulk-change').on 'click.bulk-change', => @hide() - @$el.css - top: jQuery('.navigator-actions').offset().top + jQuery('.navigator-actions').height() + 1 - left: jQuery('.navigator-actions').offset().left + jQuery('.navigator-actions').outerWidth() - @$el.outerWidth() - - - toggle: -> - if @$el.is(':visible') then @hide() else @show() - - - show: -> - @render() - @$el.show() - - - hide: -> - @$el.hide() - - - serializeData: -> - languages = @options.app.languageFilter.get('value') - activationValues = @options.app.activationFilter.get('value') or [] - qualityProfile = @options.app.getQualityProfile() - - qualityProfile: qualityProfile - qualityProfileName: @options.app.qualityProfileFilter.view.renderValue() - singleLanguage: _.isArray(languages) and languages.length == 1 - language: @options.app.languageFilter.view.renderValue() - allowActivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'false') - allowDeactivateOnProfile: qualityProfile and (activationValues.length == 0 or activationValues[0] == 'true') diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee deleted file mode 100644 index 299d8026f4f..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-bulk-change-view.coffee +++ /dev/null @@ -1,123 +0,0 @@ -define [ - 'backbone.marionette', - 'templates/coding-rules' -], ( - Marionette, - Templates -) -> - - class CodingRulesBulkChangeView extends Marionette.ItemView - template: Templates['coding-rules-bulk-change'] - - ui: - modalFooter: '.modal-foot' - modalError: '.modal-error' - modalWarning: '.modal-warning' - modalNotice: '.modal-notice' - modalField: '.modal-field' - codingRulesSubmitBulkChange: '#coding-rules-submit-bulk-change' - codingRulesCancelBulkChange: '#coding-rules-cancel-bulk-change' - codingRulesCloseBulkChange: '#coding-rules-close-bulk-change' - - events: - 'submit form': 'onSubmit' - 'click @ui.codingRulesCancelBulkChange': 'hide' - 'click @ui.codingRulesCloseBulkChange': 'close' - '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-profile').select2 - width: '250px' - minimumResultsForSearch: 1 - - show: (action, param = null) -> - @action = action - @profile = param - @render() - @$el.dialog 'open' - - - hide: -> - @$el.dialog 'close' - - - close: -> - @options.app.fetchFirstPage() - @hide() - false - - - prepareQuery: -> - _.extend @options.app.getQuery(), - wsAction: @action - profile_key: @$('#coding-rules-bulk-change-profile').val() or @profile - - - bulkChange: (query) -> - wsAction = query.wsAction - query = _.omit(query, 'wsAction') - - @ui.modalError.hide() - @ui.modalWarning.hide() - @ui.modalNotice.hide() - - origFooter = @ui.modalFooter.html() - @ui.modalFooter.html '' - - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/qualityprofiles/#{wsAction}_rules" - data: query - .done (r) => - @ui.modalField.hide() - if (r.failed) - @ui.modalWarning.show() - @ui.modalWarning.html tp('coding_rules.bulk_change.warning', r.succeeded, r.failed) - else - @ui.modalNotice.show() - @ui.modalNotice.html tp('coding_rules.bulk_change.success', r.succeeded) - - @ui.modalFooter.html origFooter - @$(@ui.codingRulesSubmitBulkChange.selector).hide() - @$(@ui.codingRulesCancelBulkChange.selector).hide() - @$(@ui.codingRulesCloseBulkChange.selector).show() - @$(@ui.codingRulesCloseBulkChange.selector).focus() - .fail => - @ui.modalFooter.html origFooter - - - onSubmit: (e) -> - e.preventDefault() - @bulkChange(@prepareQuery()) - - - getAvailableQualityProfiles: -> - languages = @options.app.languageFilter.get('value') - singleLanguage = _.isArray(languages) && languages.length == 1 - - if singleLanguage - @options.app.getQualityProfilesForLanguage(languages[0]) - else - @options.app.qualityProfiles - - serializeData: -> - action: @action - - paging: @options.app.codingRules.paging - qualityProfiles: @options.app.qualityProfiles - - qualityProfile: @profile - qualityProfileName: @options.app.qualityProfileFilter.view.renderValue() - - availableQualityProfiles: @getAvailableQualityProfiles() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-custom-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-custom-rule-creation-view.coffee deleted file mode 100644 index 69df942c423..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-custom-rule-creation-view.coffee +++ /dev/null @@ -1,179 +0,0 @@ -define [ - 'backbone.marionette', - 'templates/coding-rules' -], ( - Marionette, - Templates -) -> - - class CodingRulesCustomRuleCreationView extends Marionette.ItemView - className: 'coding-rules-modal' - template: Templates['coding-rules-custom-rule-creation'] - - - ui: - customRuleCreationKey: '#coding-rules-custom-rule-creation-key' - customRuleCreationName: '#coding-rules-custom-rule-creation-name' - customRuleCreationHtmlDescription: '#coding-rules-custom-rule-creation-html-description' - customRuleCreationSeverity: '#coding-rules-custom-rule-creation-severity' - customRuleCreationStatus: '#coding-rules-custom-rule-creation-status' - customRuleCreationParameters: '[name]' - customRuleCreationCreate: '#coding-rules-custom-rule-creation-create' - customRuleCreationReactivate: '#coding-rules-custom-rule-creation-reactivate' - modalFoot: '.modal-foot' - - - events: - 'input @ui.customRuleCreationName': 'generateKey' - 'keydown @ui.customRuleCreationName': 'generateKey' - 'keyup @ui.customRuleCreationName': 'generateKey' - - 'input @ui.customRuleCreationKey': 'flagKey' - 'keydown @ui.customRuleCreationKey': 'flagKey' - 'keyup @ui.customRuleCreationKey': 'flagKey' - - 'click #coding-rules-custom-rule-creation-cancel': 'hide' - 'click @ui.customRuleCreationCreate': 'create' - 'click @ui.customRuleCreationReactivate': 'reactivate' - - - generateKey: -> - unless @keyModifiedByUser - if @ui.customRuleCreationKey - generatedKey = @ui.customRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_') - @ui.customRuleCreationKey.val generatedKey - - flagKey: -> - @keyModifiedByUser = true - # Cannot use @ui.customRuleCreationReactivate.hide() directly since it was not there at initial render - jQuery(@ui.customRuleCreationReactivate.selector).hide() - - - create: -> - action = 'create' - if @model and @model.has 'key' - action = 'update' - - postData = - name: @ui.customRuleCreationName.val() - markdown_description: @ui.customRuleCreationHtmlDescription.val() - severity: @ui.customRuleCreationSeverity.val() - status: @ui.customRuleCreationStatus.val() - - if @model && @model.has 'key' - postData.key = @model.get 'key' - else - postData.template_key = @templateRule.get 'key' - postData.custom_key = @ui.customRuleCreationKey.val() - postData.prevent_reactivation = true - - params = @ui.customRuleCreationParameters.map(-> - node = jQuery(@) - value = node.val() - if !value and action == 'create' - value = node.prop('placeholder') || '' - key: node.prop('name'), value: value).get() - - postData.params = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';') - @sendRequest(action, postData) - - - reactivate: -> - postData = - name: @existingRule.name - markdown_description: @existingRule.mdDesc - severity: @existingRule.severity - status: @existingRule.status - template_key: @existingRule.templateKey - custom_key: @ui.customRuleCreationKey.val() - prevent_reactivation: false - - params = @existingRule.params - postData.params = (params.map (param) -> param.key + '=' + param.defaultValue).join(';') - - @sendRequest('create', postData) - - - sendRequest: (action, postData) -> - @$('.modal-error').hide() - @$('.modal-warning').hide() - - origFooter = @ui.modalFoot.html() - @ui.modalFoot.html '' - - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/rules/" + action - data: postData - error: () -> - .done (r) => - delete @templateRule - @options.app.showRule r.rule.key - @hide() - .fail (jqXHR, textStatus, errorThrown) => - if jqXHR.status == 409 - @existingRule = jqXHR.responseJSON.rule - @$('.modal-warning').show() - @ui.modalFoot.html Templates['coding-rules-custom-rule-reactivation'](@) - else - jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown) - @ui.modalFoot.html origFooter - - - onRender: -> - @$el.dialog - dialogClass: 'no-close', - width: '600px', - draggable: false, - autoOpen: false, - modal: true, - minHeight: 50, - resizable: false, - title: null - - @keyModifiedByUser = false - - format = (state) -> - return state.text unless state.id - " #{state.text}" - - severity = (@model && @model.get 'severity') || @templateRule.get 'severity' - @ui.customRuleCreationSeverity.val severity - @ui.customRuleCreationSeverity.select2 - width: '250px' - minimumResultsForSearch: 999 - formatResult: format - formatSelection: format - - status = (@model && @model.get 'status') || @templateRule.get 'status' - @ui.customRuleCreationStatus.val status - @ui.customRuleCreationStatus.select2 - width: '250px' - minimumResultsForSearch: 999 - - - show: -> - @render() - @$el.dialog 'open' - - - hide: -> - @$el.dialog 'close' - - - serializeData: -> - params = {} - if @templateRule - params = @templateRule.get 'params' - else if @model and @model.has 'params' - params = @model.get('params').map (p) -> - _.extend p, - value: p.defaultValue - - _.extend super, - change: @model && @model.has 'key' - params: params - severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'] - statuses: _.map @options.app.statuses, (value, key) -> - id: key - text: value diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-debt-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-debt-popup-view.coffee deleted file mode 100644 index c8882d87fb4..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-debt-popup-view.coffee +++ /dev/null @@ -1,16 +0,0 @@ -define [ - 'backbone.marionette' - 'templates/coding-rules' - 'common/popup' -], ( - Marionette - Templates - Popup -) -> - - class CodingRulesDebtPopupView extends Popup - template: Templates['coding-rules-debt-popup'] - - serializeData: -> - _.extend super, - subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar') diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rule-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rule-view.coffee deleted file mode 100644 index 216704641ef..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rule-view.coffee +++ /dev/null @@ -1,42 +0,0 @@ -define [ - 'backbone.marionette' - 'templates/coding-rules' -], ( - Marionette - Templates -) -> - - class CodingRulesDetailCustomRuleView extends Marionette.ItemView - tagName: 'tr' - className: 'coding-rules-detail-custom-rule' - template: Templates['coding-rules-detail-custom-rule'] - - ui: - delete: '.coding-rules-detail-custom-rule-delete' - - events: - 'click @ui.delete': 'delete' - - delete: -> - confirmDialog - title: t 'delete' - html: t 'are_you_sure' - yesHandler: => - origEl = @$el.html() - @$el.html '' - - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/rules/delete" - data: - key: @model.get 'key' - .done => - templateKey = @options.templateKey or @options.templateRule.get 'key' - @options.app.showRule templateKey - .fail => - @$el.html origEl - - serializeData: -> - _.extend super, - templateRule: @options.templateRule - canWrite: @options.app.canWrite diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rules-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rules-view.coffee deleted file mode 100644 index e43d4ca0e93..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-custom-rules-view.coffee +++ /dev/null @@ -1,16 +0,0 @@ -define [ - 'backbone.marionette' - 'coding-rules/views/coding-rules-detail-custom-rule-view' -], ( - Marionette - CodingRulesDetailCustomRuleView -) -> - - class CodingRulesDetailCustomRulesView extends Marionette.CollectionView - tagName: 'table' - className: 'width100' - itemView: CodingRulesDetailCustomRuleView - - itemViewOptions: -> - app: @options.app - templateRule: @options.templateRule diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee deleted file mode 100644 index 7a1544bc9c4..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profile-view.coffee +++ /dev/null @@ -1,101 +0,0 @@ -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'] - - - modelEvents: - 'change': 'render' - - - ui: - change: '.coding-rules-detail-quality-profile-change' - revert: '.coding-rules-detail-quality-profile-revert' - deactivate: '.coding-rules-detail-quality-profile-deactivate' - - - events: - 'click @ui.change': 'change' - 'click @ui.revert': 'revert' - 'click @ui.deactivate': 'deactivate' - - - change: -> - @options.app.codingRulesQualityProfileActivationView.model = @model - @options.app.codingRulesQualityProfileActivationView.show() - - - revert: -> - ruleKey = @options.rule.get('key') - confirmDialog - title: t 'coding_rules.revert_to_parent_definition' - html: tp 'coding_rules.revert_to_parent_definition.confirm', @getParent().name - yesHandler: => - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/qualityprofiles/activate_rule" - data: - profile_key: @model.get('qProfile') - rule_key: ruleKey - reset: true - .done => - @options.app.showRule ruleKey - - - deactivate: -> - ruleKey = @options.rule.get('key') - myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile')) - confirmDialog - title: t 'coding_rules.deactivate' - html: tp 'coding_rules.deactivate.confirm', myProfile.name - yesHandler: => - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/qualityprofiles/deactivate_rule" - data: - profile_key: @model.get('qProfile') - rule_key: ruleKey - .done => - @options.app.showRule ruleKey - - - enableUpdate: -> - @ui.update.prop 'disabled', false - - - getParent: -> - return null unless @model.get('inherit') && @model.get('inherit') != 'NONE' - myProfile = _.findWhere(@options.app.qualityProfiles, key: @model.get('qProfile')) - parentKey = myProfile.parentKey - parent = _.extend {}, _.findWhere(@options.app.qualityProfiles, key: parentKey) - parentActiveInfo = @model.collection.findWhere(qProfile: parentKey) or new Backbone.Model() - _.extend parent, parentActiveInfo.toJSON() - parent - - - enhanceParameters: -> - parent = @getParent() - params = _.sortBy(@model.get('params'), 'key') - return params unless parent - params.map (p) -> - parentParam = _.findWhere(parent.params, key: p.key) - if parentParam - _.extend p, original: _.findWhere(parent.params, key: p.key).value - else - p - - - serializeData: -> - hash = _.extend super, - parent: @getParent() - parameters: @enhanceParameters() - canWrite: @options.app.canWrite - templateKey: @options.rule.get 'templateKey' - isTemplate: @options.rule.get 'isTemplate' diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee deleted file mode 100644 index 1a5a9f69462..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-quality-profiles-view.coffee +++ /dev/null @@ -1,15 +0,0 @@ -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 - rule: @options.rule - qualityProfiles: @collection diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee deleted file mode 100644 index d9697a317d3..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-detail-view.coffee +++ /dev/null @@ -1,344 +0,0 @@ -define [ - 'backbone' - 'backbone.marionette' - 'coding-rules/views/coding-rules-detail-quality-profiles-view' - 'coding-rules/views/coding-rules-detail-quality-profile-view' - 'coding-rules/views/coding-rules-detail-custom-rules-view' - 'coding-rules/views/coding-rules-detail-custom-rule-view' - 'coding-rules/views/coding-rules-parameter-popup-view' - 'coding-rules/views/coding-rules-debt-popup-view' - 'templates/coding-rules' -], ( - Backbone - Marionette - CodingRulesDetailQualityProfilesView - CodingRulesDetailQualityProfileView - CodingRulesDetailCustomRulesView - CodingRulesDetailCustomRuleView - CodingRulesParameterPopupView - CodingRulesDebtPopupView - Templates -) -> - - class CodingRulesDetailView extends Marionette.Layout - template: Templates['coding-rules-detail'] - - - regions: - qualityProfilesRegion: '#coding-rules-detail-quality-profiles' - customRulesRegion: '.coding-rules-detail-custom-rules-section' - customRulesListRegion: '#coding-rules-detail-custom-rules' - contextRegion: '.coding-rules-detail-context' - - - 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' - tagsEditCancel: '.coding-rules-details-tag-edit-cancel' - tagsList: '.coding-rules-detail-tag-list' - - subcharacteristic: '.coding-rules-subcharacteristic' - - 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' - extendDescriptionRemove: '#coding-rules-detail-extend-description-remove' - 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' - activateContextQualityProfile: '.coding-rules-detail-quality-profile-activate' - changeQualityProfile: '.coding-rules-detail-quality-profile-update' - createCustomRule: '#coding-rules-custom-rules-create' - changeCustomRule: '#coding-rules-detail-custom-rule-change' - changeManualRule: '#coding-rules-detail-manual-rule-change' - deleteCustomRule: '#coding-rules-detail-rule-delete' - - - events: - 'click @ui.tagsChange': 'changeTags' - 'click @ui.tagsEditDone': 'editDone' - 'click @ui.tagsEditCancel': 'cancelEdit' - - 'click @ui.extendDescriptionLink': 'showExtendDescriptionForm' - 'click @ui.cancelExtendDescription': 'hideExtendDescriptionForm' - 'click @ui.extendDescriptionSubmit': 'submitExtendDescription' - 'click @ui.extendDescriptionRemove': 'removeExtendedDescription' - - 'click @ui.activateQualityProfile': 'activateQualityProfile' - 'click @ui.activateContextQualityProfile': 'activateContextQualityProfile' - 'click @ui.changeQualityProfile': 'changeQualityProfile' - 'click @ui.createCustomRule': 'createCustomRule' - 'click @ui.changeCustomRule': 'changeCustomRule' - 'click @ui.changeManualRule': 'changeManualRule' - 'click @ui.deleteCustomRule': 'deleteRule' - - 'click .coding-rules-detail-parameter-name': 'toggleParameterDescription' - 'click .coding-rules-subcharacteristic': 'showDebtPopup' - - initialize: (options) -> - super options - - if @model.get 'params' - origParams = @model.get('params') - @model.set 'params', _.sortBy(origParams, 'key') - - _.map options.actives, (active) => - _.extend active, options.app.getQualityProfileByKey active.qProfile - qualityProfiles = new Backbone.Collection options.actives, - comparator: 'name' - @qualityProfilesView = new CodingRulesDetailQualityProfilesView - app: @options.app - collection: qualityProfiles - rule: @model - - unless @model.get 'isTemplate' - qualityProfileKey = @options.app.getQualityProfile() - - if qualityProfileKey - @contextProfile = qualityProfiles.findWhere qProfile: qualityProfileKey - unless @contextProfile - @contextProfile = new Backbone.Model - key: qualityProfileKey, name: @options.app.qualityProfileFilter.view.renderValue() - @contextQualityProfileView = new CodingRulesDetailQualityProfileView - app: @options.app - model: @contextProfile - rule: @model - qualityProfiles: qualityProfiles - - @listenTo @contextProfile, 'destroy', @hideContext - - onRender: -> - @$el.find('.open-modal').modal() - - if @model.get 'isTemplate' - @$(@contextRegion.el).hide() - - if _.isEmpty(@options.actives) - @$(@qualityProfilesRegion.el).hide() - else - @qualityProfilesRegion.show @qualityProfilesView - - @$(@customRulesRegion.el).show() - customRulesOriginal = @$(@customRulesRegion.el).html() - - @$(@customRulesRegion.el).html '' - - customRules = new Backbone.Collection() - jQuery.ajax - url: "#{baseUrl}/api/rules/search" - data: - template_key: @model.get 'key' - f: 'name,severity,params' - .done (r) => - customRules.add r.rules - - # Protect against element disappearing due to navigation - if @customRulesRegion - if customRules.isEmpty() and not @options.app.canWrite - @$(@customRulesRegion.el).hide() - else - @customRulesView = new CodingRulesDetailCustomRulesView - app: @options.app - collection: customRules - templateRule: @model - @$(@customRulesRegion.el).html customRulesOriginal - @customRulesListRegion.show @customRulesView - - else - @$(@customRulesRegion.el).hide() - @$(@qualityProfilesRegion.el).show() - @qualityProfilesRegion.show @qualityProfilesView - - if @options.app.getQualityProfile() and (@options.app.canWrite or @contextProfile.has('severity')) - @$(@contextRegion.el).show() - @contextRegion.show @contextQualityProfileView - else - @$(@contextRegion.el).hide() - - that = @ - jQuery.ajax - url: "#{baseUrl}/api/rules/tags" - .done (r) => - if @ui.tagInput.select2 - # Prevent synchronization issue with navigation - @ui.tagInput.select2 - tags: _.difference (_.difference r.tags, that.model.get 'tags'), that.model.get 'sysTags' - width: '300px' - - @ui.tagsEdit.hide() - - @ui.extendDescriptionForm.hide() - @ui.extendDescriptionSpinner.hide() - - - toggleParameterDescription: (e) -> - jQuery(e.currentTarget).next('.coding-rules-detail-parameter-description').toggle(); - - - showDebtPopup: (e) -> - e.stopPropagation() - jQuery('body').click() - popup = new CodingRulesDebtPopupView - model: @model - app: @options.app - triggerEl: jQuery(e.currentTarget) - popup.render() - false - - - hideContext: -> - @contextRegion.reset() - @$(@contextRegion.el).hide() - - - changeTags: -> - if @ui.tagsEdit.show - @ui.tagsEdit.show() - if @ui.tagsList.hide - @ui.tagsList.hide() - @tagsBuffer = @ui.tagInput.select2 'val' - key.setScope 'tags' - key 'escape', 'tags', => @cancelEdit() - - - cancelEdit: -> - key.unbind 'escape', 'tags' - if @ui.tagsList.show - @ui.tagsList.show() - if @ui.tagInput.select2 - console.log @tagsBuffer - @ui.tagInput.select2 'val', @tagsBuffer - @ui.tagInput.select2 'close' - if @ui.tagsEdit.hide - @ui.tagsEdit.hide() - - - editDone: -> - @ui.tagsEdit.html '' - tags = @ui.tagInput.val() - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/rules/update" - data: - key: @model.get 'key' - tags: tags - .done (r) => - @model.set 'tags', r.rule.tags - @cancelEdit() - .always => - @render() - - - showExtendDescriptionForm: -> - @ui.descriptionExtra.hide() - @ui.extendDescriptionForm.show() - key.setScope 'extraDesc' - key 'escape', 'extraDesc', => @hideExtendDescriptionForm() - @ui.extendDescriptionText.focus() - - - hideExtendDescriptionForm: -> - key.unbind 'escape', 'extraDesc' - @ui.descriptionExtra.show() - @ui.extendDescriptionForm.hide() - - - submitExtendDescription: -> - @ui.extendDescriptionForm.hide() - @ui.extendDescriptionSpinner.show() - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/rules/update" - dataType: 'json' - data: - key: @model.get 'key' - markdown_note: @ui.extendDescriptionText.val() - .done (r) => - @model.set - htmlNote: r.rule.htmlNote - mdNote: r.rule.mdNote - @render() - - - removeExtendedDescription: -> - confirmDialog - html: t 'coding_rules.remove_extended_description.confirm' - yesHandler: => - @ui.extendDescriptionText.val '' - @submitExtendDescription() - - - activateQualityProfile: -> - @options.app.codingRulesQualityProfileActivationView.model = null - @options.app.codingRulesQualityProfileActivationView.show() - - - activateContextQualityProfile: -> - @options.app.codingRulesQualityProfileActivationView.model = @contextProfile - @options.app.codingRulesQualityProfileActivationView.show() - - createCustomRule: -> - @options.app.codingRulesCustomRuleCreationView.templateRule = @model - @options.app.codingRulesCustomRuleCreationView.model = new Backbone.Model() - @options.app.codingRulesCustomRuleCreationView.show() - - - changeCustomRule: -> - @options.app.codingRulesCustomRuleCreationView.model = @model - @options.app.codingRulesCustomRuleCreationView.show() - - - changeManualRule: -> - @options.app.codingRulesManualRuleCreationView.model = @model - @options.app.codingRulesManualRuleCreationView.show() - - - deleteRule: -> - ruleType = if @model.has('templateKey') then 'custom' else 'manual' - confirmDialog - title: t 'delete' - html: tp "coding_rules.delete.#{ruleType}.confirm", @model.get('name') - yesHandler: => - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/rules/delete" - data: - key: @model.get 'key' - .done => - @options.app.fetchFirstPage() - .fail => - @options.app.showRule @model.get('key') - - - serializeData: -> - contextQualityProfile = @options.app.getQualityProfile() - repoKey = @model.get 'repo' - isManual = (@options.app.manualRepository().key == repoKey) - isCustom = (@model.has 'templateKey') - - qualityProfilesVisible = not isManual - if qualityProfilesVisible - if @model.get 'isTemplate' - qualityProfilesVisible = (not _.isEmpty(@options.actives)) - else - qualityProfilesVisible = (@options.app.canWrite or not _.isEmpty(@options.actives)) - - - _.extend super, - contextQualityProfile: contextQualityProfile - contextQualityProfileName: @options.app.qualityProfileFilter.view.renderValue() - qualityProfile: @contextProfile - language: @options.app.languages[@model.get 'lang'] - repository: _.find(@options.app.repositories, (repo) -> repo.key == repoKey).name - isManual: isManual - canWrite: @options.app.canWrite - isEditable: (@options.app.canWrite and (isManual or isCustom)) - qualityProfilesVisible: qualityProfilesVisible - subcharacteristic: @options.app.getSubcharacteristicName(@model.get 'debtSubChar') - createdAt: moment(@model.get 'createdAt').toDate() - allTags: _.union @model.get('sysTags'), @model.get('tags') diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee deleted file mode 100644 index a83094f7084..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee +++ /dev/null @@ -1,53 +0,0 @@ -define [ - 'backbone.marionette' - 'templates/coding-rules' -], ( - Marionette, - Templates -) -> - - class CodingRulesFacetsView extends Marionette.ItemView - template: Templates['coding-rules-facets'] - - - ui: - facets: '.navigator-facets-list-item' - options: '.facet' - - - events: - 'click @ui.options': 'selectOption' - - - initialize: -> - super() - that = @ - @options.collection.each (facet) -> - property = facet.get 'property' - facet.set 'property_message', t 'coding_rules.facets.' + property - facet.set 'limitReached', facet.get('values').length >= 10 - _.each(facet.get('values'), (value) -> - value.text = that.options.app.facetLabel(property, value.val) - ) - - selectOption: (e) -> - option = jQuery(e.currentTarget) - option.toggleClass 'active' - property = option.closest('.navigator-facets-list-item').data('property') - value = option.data('key') - @options.app.filterBarView.toggle(property, value) - @applyOptions() - - - applyOptions: -> - @options.app.fetchFirstPage() - - - restoreFromQuery: (params) -> - @ui.options.each -> - jQuery(@).removeClass('active') - @ui.facets.each -> - property = jQuery(@).data 'property' - if !!params[property] - _(params[property].split(',')).map (value) -> - jQuery('.navigator-facets-list-item[data-property="' + property + '"] .facet[data-key="' + value + '"]').addClass 'active' diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee deleted file mode 100644 index c3eb8d48c4e..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-empty-view.coffee +++ /dev/null @@ -1,12 +0,0 @@ -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/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee deleted file mode 100644 index 0c77a630538..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-item-view.coffee +++ /dev/null @@ -1,31 +0,0 @@ -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: -> - @options.listView.selectIssue @$el - @options.app.showRule @model.get('key') - - - serializeData: -> - tags = _.union @model.get('sysTags'), @model.get('tags') - _.extend super, - manualRuleLabel: t 'coding_rules.manual_rule' - allTags: tags - showDetails: (@model.get('status') != 'READY') || (_.isArray(tags) && tags.length > 0) diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee deleted file mode 100644 index b62e4a28866..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-list-view.coffee +++ /dev/null @@ -1,93 +0,0 @@ -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 - - - initialize: -> - openRule = (el) -> el.click() - @openRule = _.debounce openRule, 300 - key.setScope 'list' - - - onRender: -> - key 'up', 'list', (e) => - @selectPrev() - #e.stopPropagation() - key 'down', 'list', (e) => - @selectNext() - #e.stopPropagation() - - $scrollEl = jQuery('.navigator-results') - scrollEl = $scrollEl.get(0) - onScroll = => - if scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight - @options.app.fetchNextPage() - throttledScroll = _.throttle onScroll, 300 - $scrollEl.off('scroll').on 'scroll', throttledScroll - - - onClose: -> - @unbindEvents() - - - unbindEvents: -> - key.unbind 'up', 'list' - key.unbind 'down', 'list' - - - selectIssue: (el, open) -> - @$('.active').removeClass 'active' - el.addClass 'active' - ruleKey = el.find('[name]').attr('name') - rule = @collection.findWhere key: ruleKey - @selected = @collection.indexOf(rule) - @openRule el if open - - - selectFirst: -> - @selected = -1 - @selectNext() - - - selectCurrent: -> - @selected-- - @selectNext() - - - selectNext: -> - if @selected + 1 < @collection.length - @selected += 1 - child = @$el.children().eq(@selected) - container = jQuery('.navigator-results') - containerHeight = container.height() - bottom = child.position().top + child.outerHeight() - if bottom > containerHeight - container.scrollTop(container.scrollTop() - containerHeight + bottom) - @selectIssue child, true - - - selectPrev: -> - if @selected > 0 - @selected -= 1 - child = @$el.children().eq(@selected) - container = jQuery('.navigator-results') - top = child.position().top - if top < 0 - container.scrollTop(container.scrollTop() + top) - @selectIssue child, true diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-manual-rule-creation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-manual-rule-creation-view.coffee deleted file mode 100644 index fdae346c422..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-manual-rule-creation-view.coffee +++ /dev/null @@ -1,133 +0,0 @@ -define [ - 'backbone.marionette', - 'templates/coding-rules' -], ( - Marionette, - Templates -) -> - - class CodingRulesManualRuleCreationView extends Marionette.ItemView - template: Templates['coding-rules-manual-rule-creation'] - - - ui: - manualRuleCreationKey: '#coding-rules-manual-rule-creation-key' - manualRuleCreationName: '#coding-rules-manual-rule-creation-name' - manualRuleCreationHtmlDescription: '#coding-rules-manual-rule-creation-html-description' - manualRuleCreationSeverity: '#coding-rules-manual-rule-creation-severity' - manualRuleCreationStatus: '#coding-rules-manual-rule-creation-status' - manualRuleCreationParameters: '[name]' - manualRuleCreationCreate: '#coding-rules-manual-rule-creation-create' - manualRuleCreationReactivate: '#coding-rules-manual-rule-creation-reactivate' - modalFoot: '.modal-foot' - - - events: - 'input @ui.manualRuleCreationName': 'generateKey' - 'keydown @ui.manualRuleCreationName': 'generateKey' - 'keyup @ui.manualRuleCreationName': 'generateKey' - - 'input @ui.manualRuleCreationKey': 'flagKey' - 'keydown @ui.manualRuleCreationKey': 'flagKey' - 'keyup @ui.manualRuleCreationKey': 'flagKey' - - 'click #coding-rules-manual-rule-creation-cancel': 'hide' - 'click @ui.manualRuleCreationCreate': 'create' - 'click @ui.manualRuleCreationReactivate': 'reactivate' - - - generateKey: -> - unless @keyModifiedByUser - if @ui.manualRuleCreationKey - generatedKey = @ui.manualRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_') - @ui.manualRuleCreationKey.val generatedKey - - flagKey: -> - @keyModifiedByUser = true - # Cannot use @ui.manualRuleCreationReactivate.hide() directly since it was not there at initial render - jQuery(@ui.manualRuleCreationReactivate.selector).hide() - - - create: -> - action = 'create' - if @model and @model.has 'key' - action = 'update' - - postData = - name: @ui.manualRuleCreationName.val() - markdown_description: @ui.manualRuleCreationHtmlDescription.val() - - if @model && @model.has 'key' - postData.key = @model.get 'key' - else - postData.manual_key = @ui.manualRuleCreationKey.val() - postData.prevent_reactivation = true - - @sendRequest(action, postData) - - - reactivate: -> - postData = - name: @existingRule.name - markdown_description: @existingRule.mdDesc - manual_key: @ui.manualRuleCreationKey.val() - prevent_reactivation: false - - @sendRequest('create', postData) - - - sendRequest: (action, postData) -> - @$('.modal-error').hide() - @$('.modal-warning').hide() - - origFooter = @ui.modalFoot.html() - @ui.modalFoot.html '' - - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/rules/" + action - data: postData - error: () -> - .done (r) => - @options.app.showRule r.rule.key - @hide() - .fail (jqXHR, textStatus, errorThrown) => - if jqXHR.status == 409 - @existingRule = jqXHR.responseJSON.rule - @$('.modal-warning').show() - @ui.modalFoot.html Templates['coding-rules-manual-rule-reactivation'](@) - else - jQuery.ajaxSettings.error(jqXHR, textStatus, errorThrown) - @ui.modalFoot.html origFooter - - - onRender: -> - @$el.dialog - dialogClass: 'no-close', - width: '600px', - draggable: false, - autoOpen: false, - modal: true, - minHeight: 50, - resizable: false, - title: null - - @keyModifiedByUser = false - - format = (state) -> - return state.text unless state.id - " #{state.text}" - - - show: -> - @render() - @$el.dialog 'open' - - - hide: -> - @$el.dialog 'close' - - - serializeData: -> - _.extend super, - change: @model && @model.has 'key' diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-parameter-popup-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-parameter-popup-view.coffee deleted file mode 100644 index 52ece5db2a9..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-parameter-popup-view.coffee +++ /dev/null @@ -1,15 +0,0 @@ -define [ - 'backbone.marionette' - 'templates/coding-rules' - 'common/popup' -], ( - Marionette - Templates - Popup -) -> - - $ = jQuery - - - class CodingRulesParameterPopupView extends Popup - template: Templates['coding-rules-parameter-popup'] diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee deleted file mode 100644 index 9660c29a5c7..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-quality-profile-activation-view.coffee +++ /dev/null @@ -1,124 +0,0 @@ -define [ - 'backbone.marionette', - 'templates/coding-rules' -], ( - Marionette, - Templates -) -> - - class CodingRulesQualityProfileActivationView extends Marionette.ItemView - className: 'coding-rules-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' - qualityProfileParameters: '[name]' - - - events: - 'click #coding-rules-quality-profile-activation-cancel': 'hide' - 'click @ui.qualityProfileActivate': 'activate' - - - activate: -> - profileKey = @ui.qualityProfileSelect.val() - params = @ui.qualityProfileParameters.map(-> - key: jQuery(@).prop('name'), value: jQuery(@).val() || jQuery(@).prop('placeholder') || '').get() - - paramsHash = (params.map (param) -> param.key + '=' + window.csvEscape(param.value)).join(';') - - if @model - profileKey = @model.get('qProfile') - unless profileKey - profileKey = @model.get('key') - severity = @ui.qualityProfileSeverity.val() - - origFooter = @$('.modal-foot').html() - @$('.modal-foot').html '' - - ruleKey = @rule.get('key') - jQuery.ajax - type: 'POST' - url: "#{baseUrl}/api/qualityprofiles/activate_rule" - data: - profile_key: profileKey - rule_key: ruleKey - severity: severity - params: paramsHash - .done => - @options.app.showRule ruleKey - @hide() - .fail => - @$('.modal-foot').html origFooter - - - 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 - " #{state.text}" - - severity = (@model && @model.get 'severity') || @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: (lang) -> - activeQualityProfiles = @options.app.detailView.qualityProfilesView.collection - inactiveProfiles = _.reject @options.app.qualityProfiles, (profile) => - activeQualityProfiles.findWhere key: profile.key - _.filter inactiveProfiles, (profile) => - profile.lang == lang - - - serializeData: -> - params = @rule.get 'params' - if @model - modelParams = @model.get 'params' - if modelParams - params = params.map (p) -> - parentParam = _.findWhere(modelParams, key: p.key) - if parentParam - _.extend p, value: _.findWhere(modelParams, key: p.key).value - else - p - - availableProfiles = @getAvailableQualityProfiles(@rule.get 'lang') - - _.extend super, - rule: @rule.toJSON() - change: @model && @model.has 'severity' - params: params - qualityProfiles: availableProfiles - severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'] - saveEnabled: not _.isEmpty(availableProfiles) or (@model and @model.get('qProfile')) - isCustomRule: (@model and @model.has('templateKey')) or @rule.has 'templateKey' diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee deleted file mode 100644 index b01ee86ab85..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee +++ /dev/null @@ -1,97 +0,0 @@ -define [ - 'navigator/filters/filter-bar', - 'navigator/filters/base-filters', - 'navigator/filters/favorite-filters', - 'navigator/filters/more-criteria-filters', - 'navigator/filters/read-only-filters', - 'templates/coding-rules' -], ( - FilterBarView, - BaseFilters, - FavoriteFiltersModule, - MoreCriteriaFilters, - ReadOnlyFilterView, - Templates -) -> - - class CodingRulesFilterBarView extends FilterBarView - template: Templates['coding-rules-filter-bar'] - - collectionEvents: - 'change:enabled': 'changeEnabled' - - - events: - 'click .navigator-filter-submit': 'search' - - - onRender: -> - @selectFirst() - - - 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: -> - readOnlyFilters = @collection.where(type: ReadOnlyFilterView) - disabledFilters = _.difference(@collection.where(enabled: false), readOnlyFilters) - 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') in [MoreCriteriaFilters.MoreCriteriaFilterView, ReadOnlyFilterView] - - 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: -> - @$('.navigator-filter-submit').blur() - @options.app.state.set - query: this.options.app.getQuery(), - search: true - @options.app.fetchFirstPage() - - - fetchNextPage: -> - @options.app.fetchNextPage() - - - restoreFromWsQuery: (query) -> - params = _.map(query, (value, key) -> - 'key': key - 'value': value - ) - @restoreFromQuery params - - - toggle: (property, value) -> - filter = @collection.findWhere(property: property) - unless filter.view.isActive() - @moreCriteriaFilter.view.detailsView.enableByProperty(property) - choice = filter.view.choices.get(value) - choice.set 'checked', !choice.get('checked') - filter.view.detailsView.updateValue() - filter.view.detailsView.updateLists() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee deleted file mode 100644 index da9e451a8c6..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee +++ /dev/null @@ -1,32 +0,0 @@ -define [ - 'coding-rules/views/filters/profile-dependent-filter-view' -], ( - ProfileDependentFilterView -) -> - - class ActivationFilterView extends ProfileDependentFilterView - tooltip: 'coding_rules.filters.activation.help' - - - makeActive: -> - super - filterValue = @model.get 'value' - if !filterValue or filterValue.length == 0 - @choices.each (model) -> model.set 'checked', model.id == 'true' - @model.set 'value', ['true'] - @detailsView.updateLists() - - - - showDetails: -> - super unless @$el.is '.navigator-filter-inactive' - - - restore: (value) -> - value = value.split(',') if _.isString(value) - if @choices && value.length > 0 - @choices.each (model) -> model.set 'checked', value.indexOf(model.id) >= 0 - @model.set value: value, enabled: true - @onChangeQualityProfile() - else - @clear() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/active-severities-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/active-severities-filter-view.coffee deleted file mode 100644 index 8cbe81e9e50..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/active-severities-filter-view.coffee +++ /dev/null @@ -1,9 +0,0 @@ - -define [ - 'coding-rules/views/filters/profile-dependent-filter-view' -], ( - ProfileDependentFilterView -) -> - - class ActiveSeveritiesFilterView extends ProfileDependentFilterView - tooltip: 'coding_rules.filters.active_severity.inactive' diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee deleted file mode 100644 index efa29a733ff..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/characteristic-filter-view.coffee +++ /dev/null @@ -1,12 +0,0 @@ -define [ - 'navigator/filters/choice-filters' -], ( - ChoiceFilters -) -> - - class CharacteriticFilterView extends ChoiceFilters.ChoiceFilterView - - initialize: -> - super - @choices.comparator = 'text' - @choices.sort() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee deleted file mode 100644 index 145dc06267c..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/inheritance-filter-view.coffee +++ /dev/null @@ -1,23 +0,0 @@ -define [ - 'coding-rules/views/filters/profile-dependent-filter-view' -], ( - ProfileDependentFilterView -) -> - - class InheritanceFilterView extends ProfileDependentFilterView - tooltip: 'coding_rules.filters.inheritance.inactive' - - onChangeQualityProfile: -> - qualityProfileKey = @qualityProfileFilter.get 'value' - if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1 - qualityProfile = @options.app.getQualityProfileByKey qualityProfileKey[0] - if qualityProfile.parentKey - parentQualityProfile = @options.app.getQualityProfile qualityProfile.parentKey - if parentQualityProfile - @makeActive() - else - @makeInactive() - else - @makeInactive() - else - @makeInactive() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/language-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/language-filter-view.coffee deleted file mode 100644 index b52dcb2bbbb..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/language-filter-view.coffee +++ /dev/null @@ -1,45 +0,0 @@ -define [ - 'navigator/filters/choice-filters', - 'templates/coding-rules' -], ( - ChoiceFilters, - Templates -) -> - - class LanguageFilterView extends ChoiceFilters.ChoiceFilterView - - modelEvents: - 'change:value': 'onChangeValue' - 'change:enabled': 'focus', - - - initialize: -> - super - @choices.comparator = 'text' - @choices.sort() - @app = @model.get 'app' - @listenTo @app.qualityProfileFilter, 'change:value', @onChangeProfile - @selectedFromProfile = false - - onChangeProfile: -> - profiles = @app.qualityProfileFilter.get 'value' - if _.isArray(profiles) && profiles.length > 0 - profile = _.findWhere @app.qualityProfiles, key: profiles[0] - @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property') - @choices.each (item) -> item.set 'checked', item.id == profile.lang - @refreshValues() - @selectedFromProfile = true - else if @selectedFromProfile - @choices.each (item) -> item.set 'checked', false - @refreshValues() - - onChangeValue: -> - @selectedFromProfile = false - @renderBase() - - - refreshValues: -> - @detailsView.updateValue() - @detailsView.updateLists() - @render() - @hideDetails() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/profile-dependent-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/profile-dependent-filter-view.coffee deleted file mode 100644 index 5afad402b92..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/profile-dependent-filter-view.coffee +++ /dev/null @@ -1,57 +0,0 @@ -define [ - 'navigator/filters/choice-filters' -], ( - ChoiceFilters -) -> - - class ProfileDependentFilterView extends ChoiceFilters.ChoiceFilterView - tooltip: 'coding_rules.filters.activation.help' - - initialize: -> - super - @qualityProfileFilter = @model.get 'qualityProfileFilter' - @listenTo @qualityProfileFilter, 'change:value', @onChangeQualityProfile - @onChangeQualityProfile() - - - onChangeQualityProfile: -> - qualityProfileKey = @qualityProfileFilter.get 'value' - if _.isArray(qualityProfileKey) && qualityProfileKey.length == 1 - @makeActive() - else - @makeInactive() - - - makeActive: -> - @model.set inactive: false, title: '' - @model.trigger 'change:enabled' - @$el.removeClass('navigator-filter-inactive').prop 'title', '' - @options.filterBarView.moreCriteriaFilter.view.detailsView.enableByProperty(@detailsView.model.get 'property') - @hideDetails() - - - 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 - @choices.each (item) -> - item.set 'checked', false - _.each value, (v) => - cModel = @choices.findWhere id: v - cModel.set 'checked', true - @onChangeQualityProfile() - else - @clear() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee deleted file mode 100644 index d665930cbea..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/quality-profile-filter-view.coffee +++ /dev/null @@ -1,61 +0,0 @@ -define [ - 'navigator/filters/choice-filters', - 'templates/coding-rules' -], ( - ChoiceFilters, - Templates -) -> - - class QualityProfileDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView - itemTemplate: Templates['coding-rules-profile-filter-detail'] - - - class QualityProfileFilterView extends ChoiceFilters.ChoiceFilterView - - initialize: -> - super - detailsView: QualityProfileDetailFilterView - - @app = @model.get 'app' - - @allProfiles = @model.get 'choices' - @updateChoices @allProfiles - - @listenTo @app.languageFilter, 'change:value', @onChangeLanguage - @onChangeLanguage() - - - onChangeLanguage: -> - languages = @app.languageFilter.get 'value' - if _.isArray(languages) && languages.length > 0 - @filterLanguages(languages) - else - @updateChoices(@allProfiles) - - filterLanguages: (languages) -> - languageProfiles = _.filter( @allProfiles, (prof) -> languages.indexOf(prof.lang) >= 0 ) - @updateChoices(languageProfiles) - - - updateChoices: (collection) -> - languages = @app.languages - currentValue = @model.get('value') - @choices = new Backbone.Collection( _.map collection, (item, index) -> - new Backbone.Model - id: item.key - text: item.name - checked: false - index: index - language: languages[item.lang] - comparator: 'index' - ) - if currentValue - @restore(currentValue) - @render() - - render: -> - super - if @model.get 'value' - @$el.addClass('navigator-filter-context') - else - @$el.removeClass('navigator-filter-context') diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/query-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/query-filter-view.coffee deleted file mode 100644 index ee8e70d044b..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/query-filter-view.coffee +++ /dev/null @@ -1,81 +0,0 @@ -define [ - 'backbone', - 'backbone.marionette', - 'navigator/filters/base-filters', - 'navigator/filters/string-filters', - 'navigator/filters/choice-filters', - 'templates/coding-rules', - 'common/handlebars-extensions' -], ( - Backbone, - Marionette, - BaseFilters, - StringFilterView, - ChoiceFilters, - Templates -) -> - - class QueryFilterView extends StringFilterView - template: Templates['coding-rules-query-filter'] - className: 'navigator-filter navigator-filter-query' - - events: - 'keypress input': 'checkSubmit' - 'change input': 'change' - 'click': 'focus' - 'blur': 'blur' - - - change: (e) -> - @model.set 'value', $j(e.target).val() - @options.app.codingRules.sorting = sort: '', asc: '' - - - clear: -> - super - @focus() - - - focus: -> - @$(':input').focus(); - - - blur: -> - @$(':input').blur(); - - - serializeData: -> - return _.extend({}, @model.toJSON(), - value: this.model.get('value') || '' - ) - - - initialize: -> - super detailsView: null - @model.set('size', 25) unless @model.get 'size' - - - checkSubmit: (e) -> - if (e.which == 13) - e.preventDefault() - @change(e) - @blur() - @options.app.filterBarView.$('.navigator-filter-submit').focus() - @options.app.filterBarView.$('.navigator-filter-submit').click() - - - renderInput: -> - # Done in template - - - toggleDetails: -> - # NOP - - - isDefaultValue: -> - true - - - renderBase: -> - super - @$el.prop('title', ''); diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/repository-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/repository-filter-view.coffee deleted file mode 100644 index aeae2bea056..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/repository-filter-view.coffee +++ /dev/null @@ -1,55 +0,0 @@ -define [ - 'navigator/filters/choice-filters', - 'templates/coding-rules' -], ( - ChoiceFilters, - Templates -) -> - - class RepositoryDetailFilterView extends ChoiceFilters.DetailsChoiceFilterView - itemTemplate: Templates['coding-rules-repository-detail'] - - - class RepositoryFilterView extends ChoiceFilters.ChoiceFilterView - - initialize: -> - super - detailsView: RepositoryDetailFilterView - - @app = @model.get 'app' - - @allRepositories = @model.get 'choices' - @updateChoices @allRepositories - - @listenTo @app.languageFilter, 'change:value', @onChangeLanguage - @onChangeLanguage() - - - onChangeLanguage: -> - languages = @app.languageFilter.get 'value' - if _.isArray(languages) && languages.length > 0 - @filterLanguages(languages) - else - @updateChoices(@allRepositories) - - filterLanguages: (languages) -> - languageRepositories = _.filter( @allRepositories, (repo) -> languages.indexOf(repo.language) >= 0 ) - @updateChoices(languageRepositories) - - - updateChoices: (collection) -> - languages = @app.languages - currentValue = @model.get('value') - @choices = new Backbone.Collection( _.map collection, (item, index) -> - new Backbone.Model - id: item.key - text: item.name - checked: false - index: index - language: languages[item.language] - comparator: (item) -> - [item.get('text'), item.get('language')] - ) - if currentValue - @restore(currentValue) - @render() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/tag-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/tag-filter-view.coffee deleted file mode 100644 index 01366e7f2e4..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/tag-filter-view.coffee +++ /dev/null @@ -1,38 +0,0 @@ -define [ - 'navigator/filters/choice-filters' -], ( - ChoiceFilters -) -> - - class TagFilterView extends ChoiceFilters.ChoiceFilterView - - initialize: -> - super() - @loadTags() - # TODO Register an event handler to reload tags when they are modified on a rule - - - loadTags: -> - tagsXHR = jQuery.ajax - url: "#{baseUrl}/api/rules/tags" - async: false - - jQuery.when(tagsXHR).done (r) => - @choices = new Backbone.Collection( - _.map(r.tags, (tag) -> - new Backbone.Model - id: tag - text: tag - ), - comparator: 'text') - - if @tagToRestore - @restore(@tagToRestore) - @tagToRestore = null - @render() - - restore: (value) -> - unless @choices.isEmpty() - super(value) - else - @tagToRestore = value diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/header-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/header-view.coffee deleted file mode 100644 index caa03b54779..00000000000 --- a/server/sonar-web/src/main/coffee/coding-rules/views/header-view.coffee +++ /dev/null @@ -1,28 +0,0 @@ -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' - 'click #coding-rules-create-rule': 'createRule' - - - newSearch: -> - @options.app.router.emptyQuery() - - - createRule: -> - @options.app.createManualRule() - - - serializeData: -> - _.extend super, - 'canWrite': @options.app.canWrite diff --git a/server/sonar-web/src/main/coffee/issues/app.coffee b/server/sonar-web/src/main/coffee/issues/app.coffee index 9ae6f8b3604..c40aeee41de 100644 --- a/server/sonar-web/src/main/coffee/issues/app.coffee +++ b/server/sonar-web/src/main/coffee/issues/app.coffee @@ -22,7 +22,7 @@ requirejs [ 'issues/models/state' 'issues/layout' 'issues/models/issues' - 'issues/models/facets' + 'components/navigator/models/facets' 'issues/models/filters' 'issues/controller' @@ -70,7 +70,7 @@ requirejs [ App.addInitializer -> @state = new State() - @issues = new Issues() + @list = new Issues() @facets = new Facets() @filters = new Filters() @@ -82,7 +82,7 @@ requirejs [ App.addInitializer -> @issuesView = new WorkspaceListView app: @ - collection: @issues + collection: @list @layout.workspaceListRegion.show @issuesView @issuesView.bindScrollEvents() @@ -90,7 +90,7 @@ requirejs [ App.addInitializer -> @workspaceHeaderView = new WorkspaceHeaderView app: @ - collection: @issues + collection: @list @layout.workspaceHeaderRegion.show @workspaceHeaderView diff --git a/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee b/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee index 88dbf3311a3..31f3c0baff5 100644 --- a/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee +++ b/server/sonar-web/src/main/coffee/issues/component-viewer/main.coffee @@ -52,11 +52,11 @@ define [ selectedIssueView.find(".js-issue-#{action}").click() key 'up', 'componentViewer', => - @options.app.controller.selectPreviousIssue() + @options.app.controller.selectPrev() false key 'down', 'componentViewer', => - @options.app.controller.selectNextIssue() + @options.app.controller.selectNext() false key 'left', 'componentViewer', => @@ -88,7 +88,7 @@ define [ select: -> selected = @options.app.state.get 'selectedIndex' - selectedIssue = @options.app.issues.at selected + selectedIssue = @options.app.list.at selected if selectedIssue.get('component') == @model.get('key') @scrollToIssue selectedIssue.get('key') else @@ -99,7 +99,7 @@ define [ getSelectedIssueEl: -> selected = @options.app.state.get 'selectedIndex' return null unless selected? - selectedIssue = @options.app.issues.at selected + selectedIssue = @options.app.list.at selected return null unless selectedIssue? selectedIssueView = @$("#issue-#{selectedIssue.get('key')}") if selectedIssueView.length > 0 then selectedIssueView else null @@ -108,7 +108,7 @@ define [ selectIssue: (e) -> key = $(e.currentTarget).data 'issue-key' issue = @issues.find (issue) -> issue.get('key') == key - index = @options.app.issues.indexOf issue + index = @options.app.list.indexOf issue @options.app.state.set selectedIndex: index @@ -120,7 +120,7 @@ define [ else @unbindShortcuts() selected = @options.app.state.get 'selectedIndex' - selectedIssue = @options.app.issues.at selected + selectedIssue = @options.app.list.at selected @options.app.controller.showComponentViewer selectedIssue @@ -149,11 +149,11 @@ define [ requestIssues: -> - if @options.app.issues.last().get('component') == @model.get('key') + if @options.app.list.last().get('component') == @model.get('key') r = @options.app.controller.fetchNextPage() else r = $.Deferred().resolve().promise() r.done => - @issues.reset @options.app.issues.filter (issue) => issue.get('component') == @model.key() + @issues.reset @options.app.list.filter (issue) => issue.get('component') == @model.key() @issues.reset @limitIssues @issues @addIssuesPerLineMeta @issues @@ -174,7 +174,7 @@ define [ addNextIssuesPage: -> componentKey = @model.get 'key' - @issues.add @options.app.issues.filter (issue) => issue.get('component') == componentKey + @issues.add @options.app.list.filter (issue) => issue.get('component') == componentKey scrollToLine: (line) -> diff --git a/server/sonar-web/src/main/coffee/issues/controller.coffee b/server/sonar-web/src/main/coffee/issues/controller.coffee index d937228a9e8..4bc75e7d472 100644 --- a/server/sonar-web/src/main/coffee/issues/controller.coffee +++ b/server/sonar-web/src/main/coffee/issues/controller.coffee @@ -1,10 +1,10 @@ define [ - 'backbone.marionette' + 'components/navigator/controller' 'issues/component-viewer/main' 'issues/component-viewer/state' ], ( - Marionette + Controller ComponentViewer ComponentViewerState @@ -12,56 +12,33 @@ define [ $ = jQuery EXTRA_FIELDS = 'actions,transitions,assigneeName,reporterName,actionPlanName' - PAGE_SIZE = 50 - ALL_FACETS = ['severities', 'statuses', 'resolutions', 'projectUuids', 'moduleUuids', 'componentUuids', 'assignees', 'reporters', 'rules', - 'tags', 'languages', 'actionPlans', 'creationDate', 'issues'] FACET_DATA_FIELDS = ['components', 'projects', 'users', 'rules', 'actionPlans', 'languages'] - FACETS_FROM_SERVER = ['severities', 'statuses', 'resolutions', 'actionPlans', 'projectUuids', 'rules', 'tags' - 'assignees', 'reporters', 'componentUuids', 'languages'] - TRANSFORM = { - 'resolved': 'resolutions' - 'assigned': 'assignees' - 'planned': 'actionPlans' - 'createdAt': 'creationDate' - 'createdBefore': 'creationDate' - 'createdAfter': 'creationDate' - } - class extends Marionette.Controller - - initialize: (options) -> - @listenTo options.app.state, 'change:query', @fetchIssues - + class extends Controller + allFacets: ['severities', 'statuses', 'resolutions', 'projectUuids', 'moduleUuids', 'componentUuids', 'assignees', + 'reporters', 'rules', 'tags', 'languages', 'actionPlans', 'creationDate', 'issues'], + facetsFromServer: ['severities', 'statuses', 'resolutions', 'actionPlans', 'projectUuids', 'rules', 'tags', + 'assignees', 'reporters', 'componentUuids', 'languages'], + transform: { + 'resolved': 'resolutions' + 'assigned': 'assignees' + 'planned': 'actionPlans' + 'createdAt': 'creationDate' + 'createdBefore': 'creationDate' + 'createdAfter': 'creationDate' + }, _issuesParameters: -> p: @options.app.state.get 'page' - ps: PAGE_SIZE + ps: @pageSize s: 'FILE_LINE' asc: true extra_fields: EXTRA_FIELDS facets: @_facetsFromServer().join() - _allFacets: -> - ALL_FACETS.map (facet) -> { property: facet } - - - _enabledFacets: -> - facets = @options.app.state.get 'facets' - criteria = Object.keys @options.app.state.get 'query' - facets = facets.concat criteria - facets = facets.map (facet) -> - if TRANSFORM[facet]? then TRANSFORM[facet] else facet - facets.filter (facet) -> ALL_FACETS.indexOf(facet) != -1 - - - _facetsFromServer: -> - facets = @_enabledFacets() - facets.filter (facet) -> FACETS_FROM_SERVER.indexOf(facet) != -1 - - - fetchIssues: (firstPage = true) -> + fetchList: (firstPage = true) -> if firstPage @options.app.state.set { selectedIndex: 0, page: 1 }, { silent: true } @closeComponentViewer() @@ -72,12 +49,12 @@ define [ fetchIssuesProcess = window.process.addBackgroundProcess() $.get "#{baseUrl}/api/issues/search", data .done (r) => - issues = @options.app.issues.parseIssues r + issues = @options.app.list.parseIssues r if firstPage - @options.app.issues.reset issues + @options.app.list.reset issues else - @options.app.issues.add issues - @options.app.issues.setIndex() + @options.app.list.add issues + @options.app.list.setIndex() FACET_DATA_FIELDS.forEach (field) => @options.app.facets[field] = r[field] @options.app.facets.reset @_allFacets() @options.app.facets.add r.facets, merge: true @@ -92,11 +69,6 @@ define [ window.process.failBackgroundProcess fetchIssuesProcess - fetchNextPage: -> - @options.app.state.nextPage() - @fetchIssues false - - fetchFilters: -> $.get "#{baseUrl}/api/issue_filters/app", (r) => @options.app.state.set @@ -105,35 +77,6 @@ define [ @options.app.filters.reset r.favorites - enableFacet: (id) -> - facet = @options.app.facets.get id - if facet.has('values') || FACETS_FROM_SERVER.indexOf(id) == -1 - facet.set enabled: true - else - p = window.process.addBackgroundProcess() - @requestFacet(id) - .done => - facet.set enabled: true - window.process.finishBackgroundProcess p - .fail -> - window.process.failBackgroundProcess p - - - disableFacet: (id) -> - facet = @options.app.facets.get id - facet.set enabled: false - @options.app.facetsView.children.findByModel(facet).disable() - - - toggleFacet: (id) -> - facet = @options.app.facets.get id - if facet.get('enabled') then @disableFacet(id) else @enableFacet(id) - - - enableFacets: (facets) -> - facets.forEach @enableFacet, @ - - _mergeCollections: (a, b) -> collection = new Backbone.Collection a collection.add b, merge: true @@ -162,29 +105,17 @@ define [ @options.app.state.set filter: filter, changed: false - parseQuery: (query, separator = '|') -> - q = {} - (query || '').split(separator).forEach (t) -> - tokens = t.split('=') - if tokens[0] && tokens[1]? - q[tokens[0]] = decodeURIComponent tokens[1] + parseQuery: -> + q = super # Do not allow to modify the sorting delete q.asc delete q.s q - getQuery: (separator = '|') -> - filter = @options.app.state.get 'query' - route = [] - _.map filter, (value, property) -> - route.push "#{property}=#{encodeURIComponent value}" - route.join separator - - - getRoute: (separator = '|') -> + getRoute: -> filter = @options.app.state.get 'filter' - query = @getQuery separator + query = super if filter? if @options.app.state.get('changed') && query.length > 0 query = "id=#{filter.id}|#{query}" @@ -220,20 +151,5 @@ define [ @options.app.layout.workspaceComponentViewerRegion.reset() @options.app.layout.hideComponentViewer() @options.app.issuesView.bindScrollEvents() - @options.app.issuesView.scrollToIssue() - - - selectNextIssue: -> - index = @options.app.state.get('selectedIndex') + 1 - if index < @options.app.issues.length - @options.app.state.set selectedIndex: index - else - unless @options.app.state.get('maxResultsReached') - @fetchNextPage().done => - @options.app.state.set selectedIndex: index - + @options.app.issuesView.scrollTo() - selectPreviousIssue: -> - index = @options.app.state.get('selectedIndex') - 1 - if index >= 0 - @options.app.state.set selectedIndex: index diff --git a/server/sonar-web/src/main/coffee/issues/facets-view.coffee b/server/sonar-web/src/main/coffee/issues/facets-view.coffee index b030690c29b..78f0860d3d7 100644 --- a/server/sonar-web/src/main/coffee/issues/facets-view.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets-view.coffee @@ -1,5 +1,5 @@ define [ - 'backbone.marionette' + 'components/navigator/facets-view' 'issues/facets/base-facet' 'issues/facets/severity-facet' @@ -17,7 +17,8 @@ define [ 'issues/facets/language-facet' 'issues/facets/issue-key-facet' ], ( - Marionette + FacetsView + BaseFacet SeverityFacet StatusFacet @@ -35,9 +36,7 @@ define [ IssueKeyFacet ) -> - class extends Marionette.CollectionView - className: 'issues-facets-list' - + class extends FacetsView getItemView: (model) -> switch model.get 'property' @@ -56,17 +55,3 @@ define [ when 'languages' then LanguageFacet when 'issues' then IssueKeyFacet else BaseFacet - - - itemViewOptions: -> - app: @options.app - - - collectionEvents: -> - 'change:enabled': 'updateState' - - - updateState: -> - enabledFacets = @collection.filter (model) -> model.get('enabled') - enabledFacetIds = enabledFacets.map (model) -> model.id - @options.app.state.set facets: enabledFacetIds diff --git a/server/sonar-web/src/main/coffee/issues/facets/action-plan-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/action-plan-facet.coffee index 6ecc3a387be..4959fd2a728 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/action-plan-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/action-plan-facet.coffee @@ -17,7 +17,7 @@ define [ super value = @options.app.state.get('query')['planned'] if value? && (!value || value == 'false') - @$('.js-issues-facet').filter("[data-unplanned]").addClass 'active' + @$('.js-facet').filter("[data-unplanned]").addClass 'active' toggleFacet: (e) -> diff --git a/server/sonar-web/src/main/coffee/issues/facets/assignee-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/assignee-facet.coffee index c2f1e99ac65..43c48eb193d 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/assignee-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/assignee-facet.coffee @@ -21,7 +21,7 @@ define [ super value = @options.app.state.get('query')['assigned'] if value? && (!value || value == 'false') - @$('.js-issues-facet').filter("[data-unassigned]").addClass 'active' + @$('.js-facet').filter("[data-unassigned]").addClass 'active' toggleFacet: (e) -> @@ -54,7 +54,7 @@ define [ addCustomValue: -> property = @model.get 'property' - customValue = @$('.js-issues-custom-value').select2 'val' + customValue = @$('.js-custom-value').select2 'val' value = @getValue() value += ',' if value.length > 0 value += customValue diff --git a/server/sonar-web/src/main/coffee/issues/facets/base-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/base-facet.coffee index b13643544b2..a9781dfcbe1 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/base-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/base-facet.coffee @@ -1,69 +1,10 @@ define [ - 'backbone.marionette' + 'components/navigator/facets/base-facet' 'templates/issues' ], ( - Marionette + BaseFacet Templates ) -> - $ = jQuery - - - class extends Marionette.ItemView - className: 'issues-facet-box' + class extends BaseFacet template: Templates['issues-base-facet'] - - - modelEvents: -> - 'change': 'render' - - - events: -> - 'click .js-issues-facet-toggle': 'toggle' - 'click .js-issues-facet': 'toggleFacet' - - - onRender: -> - @$el.toggleClass 'issues-facet-box-collapsed', !@model.get('enabled') - - property = @model.get 'property' - value = @options.app.state.get('query')[property] - if typeof value == 'string' - value.split(',').forEach (s) => - facet = @$('.js-issues-facet').filter("[data-value='#{s}']") - if facet.length > 0 - parent = facet.parent() - facet.addClass('active')#.detach().prependTo parent - - - toggle: -> - @options.app.controller.toggleFacet @model.id - - - getValue: -> - @$('.js-issues-facet.active').map(-> $(@).data 'value').get().join() - - - toggleFacet: (e) -> - $(e.currentTarget).toggleClass 'active' - property = @model.get 'property' - value = @getValue() - obj = {} - obj[property] = value - @options.app.state.updateFilter obj - - - disable: -> - property = @model.get 'property' - obj = {} - obj[property] = null - @options.app.state.updateFilter obj - - - sortValues: (values) -> - _.sortBy values, (v) -> -v.count - - - serializeData: -> - _.extend super, - values: @sortValues @model.getValues() diff --git a/server/sonar-web/src/main/coffee/issues/facets/creation-date-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/creation-date-facet.coffee index 2fd4c8f53a6..21ed4e09a3d 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/creation-date-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/creation-date-facet.coffee @@ -19,7 +19,7 @@ define [ onRender: -> - @$el.toggleClass 'issues-facet-box-collapsed', !@model.get('enabled') + @$el.toggleClass 'search-navigator-facet-box-collapsed', !@model.get('enabled') @$('input').datepicker dateFormat: 'yy-mm-dd' diff --git a/server/sonar-web/src/main/coffee/issues/facets/custom-values-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/custom-values-facet.coffee index 6a75a0cd776..6712695e8f2 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/custom-values-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/custom-values-facet.coffee @@ -13,7 +13,7 @@ define [ events: -> _.extend super, - 'change .js-issues-custom-value': 'addCustomValue' + 'change .js-custom-value': 'addCustomValue' getUrl: -> @@ -42,7 +42,7 @@ define [ addCustomValue: -> property = @model.get 'property' - customValue = @$('.js-issues-custom-value').select2 'val' + customValue = @$('.js-custom-value').select2 'val' value = @getValue() value += ',' if value.length > 0 value += customValue diff --git a/server/sonar-web/src/main/coffee/issues/facets/resolution-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/resolution-facet.coffee index b017d613157..ed3bb7e5450 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/resolution-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/resolution-facet.coffee @@ -18,7 +18,7 @@ define [ value = @options.app.state.get('query')['resolved'] if value? && (!value || value == 'false') - @$('.js-issues-facet').filter("[data-unresolved]").addClass 'active' + @$('.js-facet').filter("[data-unresolved]").addClass 'active' toggleFacet: (e) -> diff --git a/server/sonar-web/src/main/coffee/issues/facets/rule-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/rule-facet.coffee index c4db10359f9..ec4a576d8ec 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/rule-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/rule-facet.coffee @@ -12,7 +12,7 @@ define [ languages = @options.app.state.get('query').languages if languages? url += "&languages=#{languages}" - @$('.js-issues-custom-value').select2 + @$('.js-custom-value').select2 placeholder: 'Search...' minimumInputLength: 2 allowClear: false diff --git a/server/sonar-web/src/main/coffee/issues/facets/tag-facet.coffee b/server/sonar-web/src/main/coffee/issues/facets/tag-facet.coffee index 159c0169356..81b3c33f3f9 100644 --- a/server/sonar-web/src/main/coffee/issues/facets/tag-facet.coffee +++ b/server/sonar-web/src/main/coffee/issues/facets/tag-facet.coffee @@ -12,7 +12,7 @@ define [ tags = @options.app.state.get('query').tags if tags? url += "&tags=#{tags}" - @$('.js-issues-custom-value').select2 + @$('.js-custom-value').select2 placeholder: 'Search...' minimumInputLength: 0 allowClear: false diff --git a/server/sonar-web/src/main/coffee/issues/filters-view.coffee b/server/sonar-web/src/main/coffee/issues/filters-view.coffee index 21d07786b85..a1dfae26087 100644 --- a/server/sonar-web/src/main/coffee/issues/filters-view.coffee +++ b/server/sonar-web/src/main/coffee/issues/filters-view.coffee @@ -14,13 +14,13 @@ define [ events: - 'click .js-issues-toggle-filters': 'toggleFilters' - 'click .js-issues-filter': 'applyFilter' - 'click #issues-new-search': 'newSearch' - 'click #issues-filter-save-as': 'saveAs' - 'click #issues-filter-save': 'save' - 'click #issues-filter-copy': 'copy' - 'click #issues-filter-edit': 'edit' + 'click .js-toggle-filters': 'toggleFilters' + 'click .js-filter': 'applyFilter' + 'click .js-new-search': 'newSearch' + 'click .js-filter-save-as': 'saveAs' + 'click .js-filter-save': 'save' + 'click .js-filter-copy': 'copy' + 'click .js-filter-edit': 'edit' initialize: (options) -> @@ -35,15 +35,15 @@ define [ onRender: -> - @$el.toggleClass 'issues-filters-selected', @options.app.state.has('filter') + @$el.toggleClass 'search-navigator-filters-selected', @options.app.state.has('filter') toggleFilters: (e) -> e.stopPropagation() - @$('.issues-filters-list').toggle() + @$('.search-navigator-filters-list').toggle() $('body').on 'click.issues-filters', => $('body').off 'click.issues-filters' - @$('.issues-filters-list').hide() + @$('.search-navigator-filters-list').hide() applyFilter: (e) -> diff --git a/server/sonar-web/src/main/coffee/issues/layout.coffee b/server/sonar-web/src/main/coffee/issues/layout.coffee index a39d515384b..85d06a2a3f1 100644 --- a/server/sonar-web/src/main/coffee/issues/layout.coffee +++ b/server/sonar-web/src/main/coffee/issues/layout.coffee @@ -15,10 +15,10 @@ define [ regions: - filtersRegion: '.issues-filters' - facetsRegion: '.issues-facets' - workspaceHeaderRegion: '.issues-workspace-header' - workspaceListRegion: '.issues-workspace-list' + filtersRegion: '.search-navigator-filters' + facetsRegion: '.search-navigator-facets' + workspaceHeaderRegion: '.search-navigator-workspace-header' + workspaceListRegion: '.search-navigator-workspace-list' workspaceComponentViewerRegion: '.issues-workspace-component-viewer' @@ -31,13 +31,13 @@ define [ onRender: -> - @$('.issues-side').isolatedScroll() + @$('.search-navigator-side').isolatedScroll() onScroll: -> scrollTop = $(window).scrollTop() - $('.issues').toggleClass 'sticky', scrollTop >= @topOffset - @$('.issues-side').css top: Math.max(0, Math.min(@topOffset - scrollTop, @topOffset)) + $('.search-navigator').toggleClass 'sticky', scrollTop >= @topOffset + @$('.search-navigator-side').css top: Math.max(0, Math.min(@topOffset - scrollTop, @topOffset)) showSpinner: (region) -> diff --git a/server/sonar-web/src/main/coffee/issues/models/state.coffee b/server/sonar-web/src/main/coffee/issues/models/state.coffee index 49040ea3c79..197104042dd 100644 --- a/server/sonar-web/src/main/coffee/issues/models/state.coffee +++ b/server/sonar-web/src/main/coffee/issues/models/state.coffee @@ -1,48 +1,14 @@ define [ - 'backbone' + 'components/navigator/models/state' ], ( - Backbone + State ) -> - class extends Backbone.Model + class extends State defaults: page: 1 maxResultsReached: false - query: {} - facets: ['severities', 'statuses', 'resolutions'] - - nextPage: -> - page = @get 'page' - @set page: page + 1 - - - cleanQuery: (query) -> - q = {} - Object.keys(query).forEach (key) -> - q[key] = query[key] if query[key] - q - - - _areQueriesEqual: (a, b) -> - equal = Object.keys(a).length == Object.keys(b).length - Object.keys(a).forEach (key) -> - equal = equal && (a[key] == b[key]) - equal - - - updateFilter: (obj) -> - oldQuery = @get('query') - query = _.extend {}, oldQuery, obj - query = @cleanQuery query - @setQuery query unless @_areQueriesEqual oldQuery, query - - - setQuery: (query) -> - @set { query: query }, { silent: true } - @set changed: true - @trigger 'change:query' - diff --git a/server/sonar-web/src/main/coffee/issues/router.coffee b/server/sonar-web/src/main/coffee/issues/router.coffee index b85773f6c43..79057861a9b 100644 --- a/server/sonar-web/src/main/coffee/issues/router.coffee +++ b/server/sonar-web/src/main/coffee/issues/router.coffee @@ -1,21 +1,18 @@ define [ - 'backbone' + 'components/navigator/router' ], ( - Backbone + Router ) -> - class extends Backbone.Router - routeSeparator: '|' - + class extends Router routes: '': 'emptyQuery' ':query': 'index' initialize: (options) -> - @options = options - @listenTo @options.app.state, 'change:query', @updateRoute - @listenTo @options.app.state, 'change:filter', @updateRoute + super + @listenTo options.app.state, 'change:filter', @updateRoute emptyQuery: -> @@ -36,9 +33,3 @@ define [ @options.app.controller.applyFilter filter else @options.app.state.setQuery query - - - updateRoute: -> - route = @options.app.controller.getRoute() - @navigate route - diff --git a/server/sonar-web/src/main/coffee/issues/workspace-header-view.coffee b/server/sonar-web/src/main/coffee/issues/workspace-header-view.coffee index ec225348f47..696261ffab1 100644 --- a/server/sonar-web/src/main/coffee/issues/workspace-header-view.coffee +++ b/server/sonar-web/src/main/coffee/issues/workspace-header-view.coffee @@ -1,36 +1,29 @@ define [ - 'backbone.marionette' + 'components/navigator/workspace-header-view' 'templates/issues' ], ( - Marionette + WorkspaceHeaderView Templates ) -> $ = jQuery - class extends Marionette.ItemView + class extends WorkspaceHeaderView template: Templates['issues-workspace-header'] - collectionEvents: - 'all': 'render' - - - events: - 'click .js-back': 'returnToList' - 'click #issues-bulk-change': 'bulkChange' - 'click #issues-reload': 'reloadIssues' - 'click .js-issues-next': 'selectNextIssue' - 'click .js-issues-prev': 'selectPrevIssue' + events: -> + _.extend super, + 'click .js-back': 'returnToList' - initialize: (options) -> - @listenTo options.app.state, 'change', @render + initialize: -> + super @_onBulkIssues = window.onBulkIssues window.onBulkIssues = => $('#modal').dialog 'close' - @options.app.controller.fetchIssues() + @options.app.controller.fetchList() onClose: -> @@ -45,21 +38,3 @@ define [ query = @options.app.controller.getQuery '&' url = "#{baseUrl}/issues/bulk_change_form?#{query}" openModalWindow url, {} - - - reloadIssues: -> - @options.app.controller.fetchIssues() - - - selectNextIssue: -> - @options.app.controller.selectNextIssue() - - - selectPrevIssue: -> - @options.app.controller.selectPreviousIssue() - - - serializeData: -> - _.extend super, - state: @options.app.state.toJSON() - diff --git a/server/sonar-web/src/main/coffee/issues/workspace-list-empty-view.coffee b/server/sonar-web/src/main/coffee/issues/workspace-list-empty-view.coffee index f6514ea9ff9..f77d383a31a 100644 --- a/server/sonar-web/src/main/coffee/issues/workspace-list-empty-view.coffee +++ b/server/sonar-web/src/main/coffee/issues/workspace-list-empty-view.coffee @@ -5,7 +5,7 @@ define [ ) -> class extends Marionette.ItemView - className: 'issues-no-results' + className: 'search-navigator-no-results' template: -> diff --git a/server/sonar-web/src/main/coffee/issues/workspace-list-item-view.coffee b/server/sonar-web/src/main/coffee/issues/workspace-list-item-view.coffee index d81b015538c..2e91d9053d3 100644 --- a/server/sonar-web/src/main/coffee/issues/workspace-list-item-view.coffee +++ b/server/sonar-web/src/main/coffee/issues/workspace-list-item-view.coffee @@ -14,13 +14,14 @@ define [ initialize: (options) -> + super @listenTo options.app.state, 'change:selectedIndex', @select onRender: -> super - @$el.addClass 'issue-navigate-right' @select() + @$el.addClass 'issue-navigate-right' select: -> diff --git a/server/sonar-web/src/main/coffee/issues/workspace-list-view.coffee b/server/sonar-web/src/main/coffee/issues/workspace-list-view.coffee index d52d55bf4d5..7b139ff35b1 100644 --- a/server/sonar-web/src/main/coffee/issues/workspace-list-view.coffee +++ b/server/sonar-web/src/main/coffee/issues/workspace-list-view.coffee @@ -1,10 +1,10 @@ define [ - 'backbone.marionette' + 'components/navigator/workspace-list-view' 'templates/issues' 'issues/workspace-list-item-view' 'issues/workspace-list-empty-view' ], ( - Marionette + WorkspaceListView Templates IssueView EmptyView @@ -17,50 +17,14 @@ define [ BOTTOM_OFFSET = 10 - class extends Marionette.CompositeView + class extends WorkspaceListView template: Templates['issues-workspace-list'] componentTemplate: Templates['issues-workspace-list-component'] itemView: IssueView - itemViewContainer: '.js-issues-list' + itemViewContainer: '.js-list' emptyView: EmptyView - ui: - loadMore: '.js-issues-more' - - - itemViewOptions: -> - app: @options.app - - - collectionEvents: - 'reset': 'scrollToTop' - - - initialize: -> - @loadMoreThrottled = _.throttle @loadMore, 1000, { trailing: false } - @listenTo @options.app.state, 'change:maxResultsReached', @toggleLoadMore - @listenTo @options.app.state, 'change:selectedIndex', @scrollToIssue - @bindShortcuts() - - - onClose: -> - @unbindScrollEvents() - @unbindShortcuts() - - - toggleLoadMore: -> - @ui.loadMore.toggle !@options.app.state.get 'maxResultsReached' - - - bindScrollEvents: -> - $(window).on 'scroll.issues-workspace-list', (=> @onScroll()) - - - unbindScrollEvents: -> - $(window).off 'scroll.issues-workspace-list' - - bindShortcuts: -> doTransition = (transition) => selectedIssue = @collection.at @options.app.state.get 'selectedIndex' @@ -74,13 +38,7 @@ define [ selectedIssueView = @children.findByModel selectedIssue selectedIssueView.$(".js-issue-#{action}").click() - key 'up', 'list', => - @options.app.controller.selectPreviousIssue() - false - - key 'down', 'list', => - @options.app.controller.selectNextIssue() - false + super key 'right,return', 'list', => selectedIssue = @collection.at @options.app.state.get 'selectedIndex' @@ -101,29 +59,7 @@ define [ key 't', 'list', -> doAction 'edit-tags' - loadMore: -> - unless @options.app.state.get 'maxResultsReached' - @unbindScrollEvents() - @options.app.controller.fetchNextPage().done => @bindScrollEvents() - - - disablePointerEvents: -> - clearTimeout @scrollTimer - $('body').addClass 'disabled-pointer-events' - @scrollTimer = setTimeout (-> $('body').removeClass 'disabled-pointer-events'), 250 - - - onScroll: -> - @disablePointerEvents() - if $(window).scrollTop() + $(window).height() >= @ui.loadMore.offset().top - @loadMoreThrottled() - - - scrollToTop: -> - @$el.scrollParent().scrollTop 0 - - - scrollToIssue: -> + scrollTo: -> selectedIssue = @collection.at @options.app.state.get 'selectedIndex' return unless selectedIssue? selectedIssueView = @children.findByModel selectedIssue diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-actions.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-actions.hbs new file mode 100644 index 00000000000..2b3d0764b93 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-actions.hbs @@ -0,0 +1,18 @@ + + + diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change-dropdown.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change-dropdown.hbs new file mode 100644 index 00000000000..3fcb25ba37a --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change-dropdown.hbs @@ -0,0 +1,25 @@ +{{! activation }} + + + {{t 'coding_rules.activate_in'}}… + + +{{#if allowActivateOnProfile}} + + {{t 'coding_rules.activate_in'}} {{qualityProfileName}} + +{{/if}} + + + +{{! deactivation }} + + + {{t 'coding_rules.deactivate_in'}}… + + +{{#if allowDeactivateOnProfile}} + + {{tp 'coding_rules.deactivate_in'}} {{qualityProfileName}} + +{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change.hbs new file mode 100644 index 00000000000..441222f7557 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-bulk-change.hbs @@ -0,0 +1,40 @@ +
+ + + + + +
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-creation.hbs new file mode 100644 index 00000000000..c1244ff82e6 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-creation.hbs @@ -0,0 +1,86 @@ +
+ + + + + +
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-reactivation.hbs new file mode 100644 index 00000000000..2de07a6a814 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-custom-rule-reactivation.hbs @@ -0,0 +1,7 @@ + + +{{t 'cancel'}} diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-debt-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-debt-popup.hbs new file mode 100644 index 00000000000..4c3b81cceda --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-debt-popup.hbs @@ -0,0 +1,28 @@ +
+
+ +
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-custom-rule.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-custom-rule.hbs new file mode 100644 index 00000000000..8bd8ba0893c --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-custom-rule.hbs @@ -0,0 +1,26 @@ + + {{name}} + + + + {{severityIcon severity}} {{t "severity" severity}} + + + + {{#each parameters}} +
+ {{key}}{{value}} +
+ {{/each}} +   + + +{{#if canWrite}} + +
+ +
+ +{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-quality-profile.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-quality-profile.hbs new file mode 100644 index 00000000000..9f398ea3f2c --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail-quality-profile.hbs @@ -0,0 +1,77 @@ + + + + + + {{#if severity}} + + + {{#unless templateKey}} + + {{/unless}} + + {{#if canWrite}} + + {{/if}} + + {{else}} + {{#if canWrite}}{{#unless isTemplate}} + + {{/unless}}{{/if}} + {{/if}} + + +
+ {{name}} + {{#if parent}} +
+ {{#eq inherit 'OVERRIDES'}} + + {{/eq}} + {{#eq inherit 'INHERITED'}} + + {{/eq}} + {{parent.name}} +
+ {{/if}} +
+ {{severityIcon severity}} {{t "severity" severity}} + {{#if parent}}{{#notEq severity parent.severity}} +
+ {{t 'coding_rules.original'}} {{t 'severity' parent.severity}} +
+ {{/notEq}}{{/if}} +
+ {{#each parameters}} +
+ {{key}}{{value}} + {{#if ../parent}}{{#notEq value original}} +
+ {{t 'coding_rules.original'}} {{original}} +
+ {{/notEq}}{{/if}} +
+ {{/each}} +   +
+
+ {{#unless isTemplate}} + + {{/unless}} + {{#if parent}} + {{#eq inherit 'OVERRIDES'}} + + {{/eq}} + {{else}} + + {{/if}} +
+
+
+ +
+
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail.hbs new file mode 100644 index 00000000000..7da358161f2 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-detail.hbs @@ -0,0 +1,166 @@ +
+ +

+ {{name}} + + {{t 'coding_rules.permalink'}} + +

+{{key}} + + + +
{{{htmlDesc}}}
+ +{{#unless isEditable}} + {{#unless isManual}} +
+
+ {{#if htmlNote}} +
{{{htmlNote}}}
{{/if}} + {{#if canWrite}}
+ +
{{/if}} +
+ + {{#if canWrite}}
+ + + + + + + + + + +
+ +
+
+ + {{#if mdNote}} + + {{/if}} +
+ {{t 'cancel'}} +
+ {{> '_markdown-tips' }} +
+
+ +
+ +
{{/if}} +
+ {{/unless}} +{{/unless}} + + +{{#if params}} +

{{t 'coding_rules.parameters'}}

+
+ {{#each params}} +
+
{{key}}
+
+

{{{htmlDesc}}}

+ {{#if ../../templateKey}} +
+ {{#if defaultValue }} + {{defaultValue}} + {{else}} + {{t 'coding_rules.parameter.empty'}} + {{/if}} +
+ {{else}} + {{#if defaultValue}} +
{{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
+ {{/if}} + {{/if}} +
+
+ {{/each}} +
+{{/if}} + +{{#if isEditable}} +
+
+ {{#if isManual}} + + {{else}} + + {{/if}} + +
+
+{{/if}} + + +{{#if isTemplate}} +
+

{{t 'coding_rules.custom_rules'}}

+ + {{#if canWrite}}
+ +
{{/if}} +
+
+{{/if}} + + +{{#if qualityProfilesVisible}} +
+

{{t 'coding_rules.quality_profiles'}}

+ + {{#if canWrite}}{{#unless isTemplate}}
+ +
{{/unless}}{{/if}} + {{#if isTemplate}} +
{{t 'coding_rules.quality_profiles.template_caption'}}
+ {{/if}} +
+
+{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-facets.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-facets.hbs new file mode 100644 index 00000000000..c274ffff513 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-facets.hbs @@ -0,0 +1,26 @@ + diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-filter-bar.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-filter-bar.hbs new file mode 100644 index 00000000000..2e0f52a1b21 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-filter-bar.hbs @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-header.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-header.hbs new file mode 100644 index 00000000000..6f539db926b --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-header.hbs @@ -0,0 +1,6 @@ +

{{t 'coding_rules.page'}}

+ + diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-layout.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-layout.hbs new file mode 100644 index 00000000000..d824a27fb19 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-layout.hbs @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-empty.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-empty.hbs new file mode 100644 index 00000000000..75e2daf75af --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-empty.hbs @@ -0,0 +1 @@ +{{t 'coding_rules.no_results'}} \ No newline at end of file diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-item.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-item.hbs new file mode 100644 index 00000000000..a4244ac7370 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-list-item.hbs @@ -0,0 +1,19 @@ +
+ {{default language manualRuleLabel}} + + {{#if allTags}} +    + + + {{join allTags ', '}} + + {{/if}} + + {{#notEq status 'READY'}} +
+ {{status}} +
+ {{/notEq}} +
+ +
{{name}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-creation.hbs new file mode 100644 index 00000000000..389dd69c661 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-creation.hbs @@ -0,0 +1,50 @@ +
+ + + + + +
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-reactivation.hbs new file mode 100644 index 00000000000..2410c7fd95f --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-manual-rule-reactivation.hbs @@ -0,0 +1,7 @@ + + +{{t 'cancel'}} diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-parameter-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-parameter-popup.hbs new file mode 100644 index 00000000000..0299cedabc2 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-parameter-popup.hbs @@ -0,0 +1,12 @@ +
+
{{key}}
+ + {{{htmlDesc}}} + {{#if defaultValue}} +
+ {{t 'coding_rules.parameters.default_value'}} {{defaultValue}} +
+ {{/if}} +
+ +
diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-profile-filter-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-profile-filter-detail.hbs new file mode 100644 index 00000000000..3a3b44cff8b --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-profile-filter-detail.hbs @@ -0,0 +1,16 @@ +
  • + +
  • diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-quality-profile-activation.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-quality-profile-activation.hbs new file mode 100644 index 00000000000..e407448a8bb --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-quality-profile-activation.hbs @@ -0,0 +1,76 @@ +
    + + + + + +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-query-filter.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-query-filter.hbs new file mode 100644 index 00000000000..392a69042f2 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-query-filter.hbs @@ -0,0 +1,3 @@ + diff --git a/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-repository-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-repository-detail.hbs new file mode 100644 index 00000000000..3a3b44cff8b --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules-old/coding-rules-repository-detail.hbs @@ -0,0 +1,16 @@ +
  • + +
  • diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-actions.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-actions.hbs deleted file mode 100644 index 2b3d0764b93..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-actions.hbs +++ /dev/null @@ -1,18 +0,0 @@ - - - diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change-dropdown.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change-dropdown.hbs deleted file mode 100644 index 3fcb25ba37a..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change-dropdown.hbs +++ /dev/null @@ -1,25 +0,0 @@ -{{! activation }} - - - {{t 'coding_rules.activate_in'}}… - - -{{#if allowActivateOnProfile}} - - {{t 'coding_rules.activate_in'}} {{qualityProfileName}} - -{{/if}} - - - -{{! deactivation }} - - - {{t 'coding_rules.deactivate_in'}}… - - -{{#if allowDeactivateOnProfile}} - - {{tp 'coding_rules.deactivate_in'}} {{qualityProfileName}} - -{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change.hbs deleted file mode 100644 index 441222f7557..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-bulk-change.hbs +++ /dev/null @@ -1,40 +0,0 @@ -
    - - - - - -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-creation.hbs deleted file mode 100644 index c1244ff82e6..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-creation.hbs +++ /dev/null @@ -1,86 +0,0 @@ -
    - - - - - -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-reactivation.hbs deleted file mode 100644 index 2de07a6a814..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-custom-rule-reactivation.hbs +++ /dev/null @@ -1,7 +0,0 @@ - - -{{t 'cancel'}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-debt-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-debt-popup.hbs deleted file mode 100644 index 4c3b81cceda..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-debt-popup.hbs +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    - -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-custom-rule.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-custom-rule.hbs deleted file mode 100644 index 8bd8ba0893c..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-custom-rule.hbs +++ /dev/null @@ -1,26 +0,0 @@ - - {{name}} - - - - {{severityIcon severity}} {{t "severity" severity}} - - - - {{#each parameters}} -
    - {{key}}{{value}} -
    - {{/each}} -   - - -{{#if canWrite}} - -
    - -
    - -{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-quality-profile.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-quality-profile.hbs deleted file mode 100644 index 9f398ea3f2c..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail-quality-profile.hbs +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - {{#if severity}} - - - {{#unless templateKey}} - - {{/unless}} - - {{#if canWrite}} - - {{/if}} - - {{else}} - {{#if canWrite}}{{#unless isTemplate}} - - {{/unless}}{{/if}} - {{/if}} - - -
    - {{name}} - {{#if parent}} -
    - {{#eq inherit 'OVERRIDES'}} - - {{/eq}} - {{#eq inherit 'INHERITED'}} - - {{/eq}} - {{parent.name}} -
    - {{/if}} -
    - {{severityIcon severity}} {{t "severity" severity}} - {{#if parent}}{{#notEq severity parent.severity}} -
    - {{t 'coding_rules.original'}} {{t 'severity' parent.severity}} -
    - {{/notEq}}{{/if}} -
    - {{#each parameters}} -
    - {{key}}{{value}} - {{#if ../parent}}{{#notEq value original}} -
    - {{t 'coding_rules.original'}} {{original}} -
    - {{/notEq}}{{/if}} -
    - {{/each}} -   -
    -
    - {{#unless isTemplate}} - - {{/unless}} - {{#if parent}} - {{#eq inherit 'OVERRIDES'}} - - {{/eq}} - {{else}} - - {{/if}} -
    -
    -
    - -
    -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail.hbs deleted file mode 100644 index 7da358161f2..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-detail.hbs +++ /dev/null @@ -1,166 +0,0 @@ -
    - -

    - {{name}} - - {{t 'coding_rules.permalink'}} - -

    -{{key}} - - - -
    {{{htmlDesc}}}
    - -{{#unless isEditable}} - {{#unless isManual}} -
    -
    - {{#if htmlNote}} -
    {{{htmlNote}}}
    {{/if}} - {{#if canWrite}}
    - -
    {{/if}} -
    - - {{#if canWrite}}
    - - - - - - - - - - -
    - -
    -
    - - {{#if mdNote}} - - {{/if}} -
    - {{t 'cancel'}} -
    - {{> '_markdown-tips' }} -
    -
    - -
    - -
    {{/if}} -
    - {{/unless}} -{{/unless}} - - -{{#if params}} -

    {{t 'coding_rules.parameters'}}

    -
    - {{#each params}} -
    -
    {{key}}
    -
    -

    {{{htmlDesc}}}

    - {{#if ../../templateKey}} -
    - {{#if defaultValue }} - {{defaultValue}} - {{else}} - {{t 'coding_rules.parameter.empty'}} - {{/if}} -
    - {{else}} - {{#if defaultValue}} -
    {{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
    - {{/if}} - {{/if}} -
    -
    - {{/each}} -
    -{{/if}} - -{{#if isEditable}} -
    -
    - {{#if isManual}} - - {{else}} - - {{/if}} - -
    -
    -{{/if}} - - -{{#if isTemplate}} -
    -

    {{t 'coding_rules.custom_rules'}}

    - - {{#if canWrite}}
    - -
    {{/if}} -
    -
    -{{/if}} - - -{{#if qualityProfilesVisible}} -
    -

    {{t 'coding_rules.quality_profiles'}}

    - - {{#if canWrite}}{{#unless isTemplate}}
    - -
    {{/unless}}{{/if}} - {{#if isTemplate}} -
    {{t 'coding_rules.quality_profiles.template_caption'}}
    - {{/if}} -
    -
    -{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-facets.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-facets.hbs deleted file mode 100644 index c274ffff513..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-facets.hbs +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filter-bar.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filter-bar.hbs deleted file mode 100644 index 2e0f52a1b21..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filter-bar.hbs +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs new file mode 100644 index 00000000000..45ce48c26c6 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs @@ -0,0 +1,9 @@ +
    + {{t 'coding_rules.page'}} +
    + +
    +
    + +
    +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-header.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-header.hbs deleted file mode 100644 index 6f539db926b..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-header.hbs +++ /dev/null @@ -1,6 +0,0 @@ -

    {{t 'coding_rules.page'}}

    - - diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-layout.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-layout.hbs index d824a27fb19..8f46e4f8fb1 100644 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-layout.hbs +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-layout.hbs @@ -1,16 +1,10 @@ - - - +
    +
    +
    +
    - \ No newline at end of file +
    +
    +
    +
    +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-empty.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-empty.hbs deleted file mode 100644 index 75e2daf75af..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-empty.hbs +++ /dev/null @@ -1 +0,0 @@ -{{t 'coding_rules.no_results'}} \ No newline at end of file diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-item.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-item.hbs deleted file mode 100644 index a4244ac7370..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-list-item.hbs +++ /dev/null @@ -1,19 +0,0 @@ -
    - {{default language manualRuleLabel}} - - {{#if allTags}} -    - - - {{join allTags ', '}} - - {{/if}} - - {{#notEq status 'READY'}} -
    - {{status}} -
    - {{/notEq}} -
    - -
    {{name}}
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-creation.hbs deleted file mode 100644 index 389dd69c661..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-creation.hbs +++ /dev/null @@ -1,50 +0,0 @@ -
    - - - - - -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-reactivation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-reactivation.hbs deleted file mode 100644 index 2410c7fd95f..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-manual-rule-reactivation.hbs +++ /dev/null @@ -1,7 +0,0 @@ - - -{{t 'cancel'}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-parameter-popup.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-parameter-popup.hbs deleted file mode 100644 index 0299cedabc2..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-parameter-popup.hbs +++ /dev/null @@ -1,12 +0,0 @@ -
    -
    {{key}}
    - - {{{htmlDesc}}} - {{#if defaultValue}} -
    - {{t 'coding_rules.parameters.default_value'}} {{defaultValue}} -
    - {{/if}} -
    - -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-profile-filter-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-profile-filter-detail.hbs deleted file mode 100644 index 3a3b44cff8b..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-profile-filter-detail.hbs +++ /dev/null @@ -1,16 +0,0 @@ -
  • - -
  • diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-quality-profile-activation.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-quality-profile-activation.hbs deleted file mode 100644 index e407448a8bb..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-quality-profile-activation.hbs +++ /dev/null @@ -1,76 +0,0 @@ -
    - - - - - -
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-query-filter.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-query-filter.hbs deleted file mode 100644 index 392a69042f2..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-query-filter.hbs +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-repository-detail.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-repository-detail.hbs deleted file mode 100644 index 3a3b44cff8b..00000000000 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-repository-detail.hbs +++ /dev/null @@ -1,16 +0,0 @@ -
  • - -
  • diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs new file mode 100644 index 00000000000..935dd66e8cb --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs @@ -0,0 +1,162 @@ +

    + {{name}} + +

    +{{key}} + + + +
    {{{htmlDesc}}}
    + +{{#unless isEditable}} + {{#unless isManual}} +
    +
    + {{#if htmlNote}} +
    {{{htmlNote}}}
    {{/if}} + {{#if canWrite}}
    + +
    {{/if}} +
    + + {{#if canWrite}}
    + + + + + + + + + + +
    + +
    +
    + + {{#if mdNote}} + + {{/if}} +
    + {{t 'cancel'}} +
    + {{> '_markdown-tips' }} +
    +
    + +
    + +
    {{/if}} +
    + {{/unless}} +{{/unless}} + + +{{#if params}} +

    {{t 'coding_rules.parameters'}}

    +
    + {{#each params}} +
    +
    {{key}}
    +
    +

    {{{htmlDesc}}}

    + {{#if ../../templateKey}} +
    + {{#if defaultValue }} + {{defaultValue}} + {{else}} + {{t 'coding_rules.parameter.empty'}} + {{/if}} +
    + {{else}} + {{#if defaultValue}} +
    {{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
    + {{/if}} + {{/if}} +
    +
    + {{/each}} +
    +{{/if}} + +{{#if isEditable}} +
    +
    + {{#if isManual}} + + {{else}} + + {{/if}} + +
    +
    +{{/if}} + + +{{#if isTemplate}} +
    +

    {{t 'coding_rules.custom_rules'}}

    + + {{#if canWrite}}
    + +
    {{/if}} +
    +
    +{{/if}} + + +{{#if qualityProfilesVisible}} +
    +

    {{t 'coding_rules.quality_profiles'}}

    + + {{#if canWrite}}{{#unless isTemplate}}
    + +
    {{/unless}}{{/if}} + {{#if isTemplate}} +
    {{t 'coding_rules.quality_profiles.template_caption'}}
    + {{/if}} +
    +
    +{{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-header.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-header.hbs new file mode 100644 index 00000000000..e91dbcd736b --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-header.hbs @@ -0,0 +1,30 @@ +
    + {{#if state.rule}} + {{t 'coding_rules.return_to_list'}} + {{else}} +   + {{/if}} +
    + + +
    + {{#notNull state.total}} +
    + {{#gt state.total 0}} + + {{sum state.selectedIndex 1}} / {{state.total}} + + {{else}} + 0 / 0 + {{/gt}} +
    + {{/notNull}} + + +
    + + {{#if state.canBulkChange}} + + {{/if}} +
    +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list-item.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list-item.hbs new file mode 100644 index 00000000000..fffa5b5e9cc --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list-item.hbs @@ -0,0 +1,15 @@ +
    +
    + {{name}} +
    +
    + {{langName}} + {{#notEmpty sysTags}} +     + + {{#each sysTags}} + {{this}} + {{/each}} + {{/notEmpty}} +
    +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list.hbs new file mode 100644 index 00000000000..37421cb75c2 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-workspace-list.hbs @@ -0,0 +1,5 @@ +
    + +
    + +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/facets/_coding-rules-facet-header.hbs b/server/sonar-web/src/main/hbs/coding-rules/facets/_coding-rules-facet-header.hbs new file mode 100644 index 00000000000..2251f570ee9 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/facets/_coding-rules-facet-header.hbs @@ -0,0 +1,4 @@ + + + {{t 'coding_rules.facet' property}} + diff --git a/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-base-facet.hbs b/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-base-facet.hbs new file mode 100644 index 00000000000..fc7fef9f205 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-base-facet.hbs @@ -0,0 +1,10 @@ +{{> '_coding-rules-facet-header'}} + +
    + {{#each values}} + + {{default label val}}{{#if extra}} {{extra}}{{/if}} + {{count}} + + {{/each}} +
    diff --git a/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-severity-facet.hbs b/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-severity-facet.hbs new file mode 100644 index 00000000000..b6a386b603b --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/facets/coding-rules-severity-facet.hbs @@ -0,0 +1,10 @@ +{{> '_coding-rules-facet-header'}} + +
    + {{#each values}} + + {{severityIcon val}} {{t 'severity' val}} + {{count}} + + {{/each}} +
    diff --git a/server/sonar-web/src/main/hbs/issues/facets/_issues-facet-header.hbs b/server/sonar-web/src/main/hbs/issues/facets/_issues-facet-header.hbs index 9b59a846155..3b57c6021ea 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/_issues-facet-header.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/_issues-facet-header.hbs @@ -1,4 +1,4 @@ - + {{t 'issues.facet' property}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-action-plan-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-action-plan-facet.hbs index d0cdd871563..1b7d6dc39a7 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-action-plan-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-action-plan-facet.hbs @@ -1,15 +1,15 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} {{#eq val ''}} {{! unplanned }} - + {{t 'issue.unplanned'}} {{count}} {{else}} - + {{label}} {{count}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-assignee-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-assignee-facet.hbs index 4fd181b9b98..6e6ab49b1d4 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-assignee-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-assignee-facet.hbs @@ -1,22 +1,22 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} {{#eq val ''}} {{! unassigned }} - + {{t 'unassigned'}} {{count}} {{else}} - + {{label}} {{count}} {{/eq}} {{/each}} -
    - +
    +
    diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-base-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-base-facet.hbs index 4fd48a68f4e..7e12ac12daa 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-base-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-base-facet.hbs @@ -1,8 +1,8 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} - + {{default label val}} {{count}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-component-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-component-facet.hbs index ec0d1bd7a6b..479bdc19abc 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-component-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-component-facet.hbs @@ -1,8 +1,8 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} - + {{default label val}} {{count}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-creation-date-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-creation-date-facet.hbs index 5e33e15dd08..c5b3e5dd47e 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-creation-date-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-creation-date-facet.hbs @@ -2,13 +2,13 @@ {{#if createdAt}} -
    +
    {{dt createdAt}} ({{fromNow createdAt}})
    {{else}} -
    - +
    + to - +
    {{/if}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-custom-values-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-custom-values-facet.hbs index 79bf7ac15bd..bb0568a8171 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-custom-values-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-custom-values-facet.hbs @@ -1,14 +1,14 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} - + {{default label val}} {{count}} {{/each}} -
    - +
    +
    diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-issue-key-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-issue-key-facet.hbs index e146f5a64e6..7d82808b911 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-issue-key-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-issue-key-facet.hbs @@ -1,5 +1,5 @@ {{> '_issues-facet-header'}} -
    +
    {{issues}}
    diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-resolution-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-resolution-facet.hbs index 1eb34815a92..72aba97d349 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-resolution-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-resolution-facet.hbs @@ -1,15 +1,15 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} {{#eq val ''}} {{! unresolved }} - + {{t 'unresolved'}} {{count}} {{else}} - + {{t 'issue.resolution' val}} {{count}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-severity-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-severity-facet.hbs index 062e275abb4..882b4780624 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-severity-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-severity-facet.hbs @@ -1,8 +1,8 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} - + {{severityIcon val}} {{t 'severity' val}} {{count}} diff --git a/server/sonar-web/src/main/hbs/issues/facets/issues-status-facet.hbs b/server/sonar-web/src/main/hbs/issues/facets/issues-status-facet.hbs index 02cc4482eec..75023f2d9aa 100644 --- a/server/sonar-web/src/main/hbs/issues/facets/issues-status-facet.hbs +++ b/server/sonar-web/src/main/hbs/issues/facets/issues-status-facet.hbs @@ -1,8 +1,8 @@ {{> '_issues-facet-header'}} -
    +
    {{#each values}} - + {{statusIcon val}} {{t 'issue.status' val}} {{count}} diff --git a/server/sonar-web/src/main/hbs/issues/issues-filters.hbs b/server/sonar-web/src/main/hbs/issues/issues-filters.hbs index b9e3266e3ca..cd51e685651 100644 --- a/server/sonar-web/src/main/hbs/issues/issues-filters.hbs +++ b/server/sonar-web/src/main/hbs/issues/issues-filters.hbs @@ -1,36 +1,36 @@ -
    +
    {{#each items}} - {{name}} + {{name}}
    {{/each}} - {{t 'manage'}} + {{t 'manage'}}
    -
    +
    {{#if state.canManageFilters}} - +  {{> '_issues-filter-name'}} {{#if filter.description}} -
    {{filter.description}}
    +
    {{filter.description}}
    {{/if}} {{else}} - {{t 'issues'}} + {{t 'issues'}} {{/if}}
    -
    +
    - + {{#if state.canManageFilters}} {{#if filter.canModify}} - {{#if state.changed}}{{/if}} + {{#if state.changed}}{{/if}} {{/if}} - {{#unless filter.id}}{{/unless}} - {{#if filter.id}}{{/if}} + {{#unless filter.id}}{{/unless}} + {{#if filter.id}}{{/if}} {{#if filter.canModify}} - {{#if filter.id}}{{/if}} + {{#if filter.id}}{{/if}} {{/if}} {{/if}}
    diff --git a/server/sonar-web/src/main/hbs/issues/issues-layout.hbs b/server/sonar-web/src/main/hbs/issues/issues-layout.hbs index dfa704a6fb8..f60fecfb03f 100644 --- a/server/sonar-web/src/main/hbs/issues/issues-layout.hbs +++ b/server/sonar-web/src/main/hbs/issues/issues-layout.hbs @@ -1,10 +1,10 @@ -
    -
    -
    +
    +
    +
    -
    -
    -
    +
    +
    +
    diff --git a/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs b/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs index d693e1d1bb5..93175e7c99b 100644 --- a/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs +++ b/server/sonar-web/src/main/hbs/issues/issues-workspace-header.hbs @@ -13,13 +13,13 @@
    -
    +
    {{#notNull state.total}} -
    +
    {{#gt state.total 0}} - + {{sum state.selectedIndex 1}} / {{state.total}} - + {{else}} 0 / 0 {{/gt}} @@ -27,10 +27,10 @@ {{/notNull}} -
    - +
    + {{#if state.canBulkChange}} - + {{/if}}
    diff --git a/server/sonar-web/src/main/hbs/issues/issues-workspace-list.hbs b/server/sonar-web/src/main/hbs/issues/issues-workspace-list.hbs index 4f9c8376ab6..37421cb75c2 100644 --- a/server/sonar-web/src/main/hbs/issues/issues-workspace-list.hbs +++ b/server/sonar-web/src/main/hbs/issues/issues-workspace-list.hbs @@ -1,5 +1,5 @@ -
    +
    -
    +
    diff --git a/server/sonar-web/src/main/js/coding-rules/app.js b/server/sonar-web/src/main/js/coding-rules/app.js new file mode 100644 index 00000000000..c42f4a41a8b --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/app.js @@ -0,0 +1,145 @@ +requirejs.config({ + baseUrl: baseUrl + '/js', + + paths: { + 'backbone': 'third-party/backbone', + 'backbone.marionette': 'third-party/backbone.marionette', + 'handlebars': 'third-party/handlebars' + }, + + shim: { + 'backbone.marionette': { + deps: ['backbone'], + exports: 'Marionette' + }, + 'backbone': { + exports: 'Backbone' + }, + 'handlebars': { + exports: 'Handlebars' + } + } +}); + + +requirejs([ + 'backbone', + 'backbone.marionette', + + 'coding-rules/models/state', + 'coding-rules/layout', + 'coding-rules/models/rules', + 'components/navigator/models/facets', + + 'coding-rules/controller', + 'components/navigator/router', + + 'coding-rules/workspace-list-view', + 'coding-rules//workspace-header-view', + + 'coding-rules/facets-view', + 'coding-rules/filters-view', + + 'common/handlebars-extensions' +], + function (Backbone, + Marionette, + State, + Layout, + Rules, + Facets, + Controller, + Router, + WorkspaceListView, + WorkspaceHeaderView, + FacetsView, + FiltersView) { + + var $ = jQuery, + App = new Marionette.Application(), + p = window.process.addBackgroundProcess(); + + App.addInitializer(function () { + this.layout = new Layout(); + $('.coding-rules').empty().append(this.layout.render().el); + }); + + App.addInitializer(function () { + this.state = new State(); + this.list = new Rules(); + this.facets = new Facets(); + }); + + App.addInitializer(function () { + this.controller = new Controller({ + app: this + }); + }); + + App.addInitializer(function () { + this.workspaceListView = new WorkspaceListView({ + app: this, + collection: this.list + }); + this.layout.workspaceListRegion.show(this.workspaceListView); + this.workspaceListView.bindScrollEvents(); + + this.workspaceHeaderView = new WorkspaceHeaderView({ + app: this, + collection: this.list + }); + this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); + + this.facetsView = new FacetsView({ + app: this, + collection: this.facets + }); + this.layout.facetsRegion.show(this.facetsView); + + this.filtersView = new FiltersView({ + app: this + }); + this.layout.filtersRegion.show(this.filtersView); + }); + + App.addInitializer(function () { + key.setScope('list'); + this.router = new Router({ + app: this + }); + Backbone.history.start(); + window.process.finishBackgroundProcess(p); + }); + + App.manualRepository = function () { + return { + key: 'manual', + name: t('coding_rules.manual_rules'), + language: 'none' + }; + }; + + App.getSubCharacteristicName = function (name) { + return (App.characteristics[name] || '').replace(': ', ' > '); + }; + + var appXHR = $.get(baseUrl + '/api/rules/app').done(function(r) { + App.canWrite = r.canWrite; + App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']); + App.languages = _.extend(r.languages, { + none: 'None' + }); + _.map(App.qualityProfiles, function(profile) { + profile.language = App.languages[profile.lang]; + }); + App.repositories = r.repositories; + App.repositories.push(App.manualRepository()); + App.statuses = r.statuses; + App.characteristics = r.characteristics; + }); + + $.when(window.requestMessages(), appXHR).done(function () { + App.start(); + }); + + }); diff --git a/server/sonar-web/src/main/js/coding-rules/controller.js b/server/sonar-web/src/main/js/coding-rules/controller.js new file mode 100644 index 00000000000..3eec23d697c --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/controller.js @@ -0,0 +1,119 @@ +define([ + 'components/navigator/controller', + 'coding-rules/rule-details-view' +], function (Controller, RuleDetailsView) { + + var $ = jQuery; + + return Controller.extend({ + allFacets: ['languages', 'repositories', 'tags', 'qprofile', 'debt_characteristics', 'severities', 'statuses'], + facetsFromServer: ['languages', 'repositories', 'tags'], + pageSize: 200, + ruleFields: ['name', 'lang', 'langName', 'sysTags', 'tags'], + + + _searchParameters: function () { + return { + p: this.app.state.get('page'), + ps: this.pageSize, + facets: true, + f: this.ruleFields.join() + }; + }, + + fetchList: function (firstPage) { + firstPage = firstPage == null ? true : firstPage; + if (firstPage) { + this.app.state.set({ selectedIndex: 0, page: 1 }, { silent: true }); + } + + var that = this, + url = baseUrl + '/api/rules/search', + options = _.extend(this._searchParameters(), this.app.state.get('query')), + p = window.process.addBackgroundProcess(); + return $.get(url, options).done(function (r) { + var rules = that.app.list.parseRules(r); + if (firstPage) { + that.app.list.reset(rules); + } else { + that.app.list.add(rules); + } + that.app.list.setIndex(); + that.app.facets.reset(that._allFacets()); + that.app.facets.add(r.facets, { merge: true }); + that.enableFacets(that._enabledFacets()); + that.app.state.set({ + page: r.p, + pageSize: r.ps, + total: r.total, + maxResultsReached: r.p * r.ps >= r.total + }); + window.process.finishBackgroundProcess(p); + }).fail(function () { + window.process.failBackgroundProcess(p); + }); + }, + + requestFacet: function (id) { + var url = baseUrl + '/api/rules/search', + facet = this.app.facets.get(id), + options = _.extend({ facets: true, ps: 1 }, this.app.state.get('query')); + return $.get(url, options).done(function (r) { + var facetData = _.findWhere(r.facets, { property: id }); + if (facetData) { + facet.set(facetData); + } + }); + }, + + parseQuery: function () { + var q = Controller.prototype.parseQuery.apply(this, arguments); + delete q.asc; + delete q.s; + return q; + }, + + getRuleDetails: function (rule) { + var url = baseUrl + '/api/rules/show', + options = { + key: rule.id, + actives: true + }; + return $.get(url, options).done(function (data) { + rule.set(data.rule); + }); + }, + + showDetails: function (rule) { + var that = this; + this.app.layout.workspaceDetailsRegion.reset(); + this.getRuleDetails(rule).done(function () { + key.setScope('details'); + that.app.workspaceListView.unbindScrollEvents(); + that.app.state.set({ rule: rule }); + that.app.workspaceDetailsView = new RuleDetailsView({ + app: that.app, + model: rule + }); + that.app.layout.workspaceDetailsRegion.show(that.app.workspaceDetailsView); + that.app.layout.showDetails(); + }); + }, + + showDetailsForSelected: function () { + var rule = this.app.list.at(this.app.state.get('selectedIndex')); + this.showDetails(rule); + }, + + hideDetails: function () { + key.setScope('list'); + this.app.state.unset('rule'); + this.app.layout.workspaceDetailsRegion.reset(); + this.app.layout.hideDetails(); + this.app.workspaceListView.bindScrollEvents(); + this.app.workspaceListView.scrollTo(); + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets-view.js b/server/sonar-web/src/main/js/coding-rules/facets-view.js new file mode 100644 index 00000000000..6c34b3939aa --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets-view.js @@ -0,0 +1,43 @@ +define([ + 'components/navigator/facets-view', + 'coding-rules/facets/base-facet', + 'coding-rules/facets/language-facet', + 'coding-rules/facets/repository-facet', + 'coding-rules/facets/quality-profile-facet', + 'coding-rules/facets/characteristic-facet', + 'coding-rules/facets/severity-facet', + 'coding-rules/facets/status-facet' +], + function (FacetsView, + BaseFacet, + LanguageFacet, + RepositoryFacet, + QualityProfileFacet, + CharacteristicFacet, + SeverityFacet, + StatusFacet) { + + return FacetsView.extend({ + + getItemView: function (model) { + switch (model.get('property')) { + case 'languages': + return LanguageFacet; + case 'repositories': + return RepositoryFacet; + case 'qprofile': + return QualityProfileFacet; + case 'debt_characteristics': + return CharacteristicFacet; + case 'severities': + return SeverityFacet; + case 'statuses': + return StatusFacet; + default: + return BaseFacet; + } + } + + }); + + }); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/base-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/base-facet.js new file mode 100644 index 00000000000..b757662d197 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/base-facet.js @@ -0,0 +1,11 @@ +define([ + 'components/navigator/facets/base-facet', + 'templates/coding-rules' +], function (BaseFacet, Templates) { + + return BaseFacet.extend({ + className: 'search-navigator-facet-box', + template: Templates['coding-rules-base-facet'] + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/characteristic-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/characteristic-facet.js new file mode 100644 index 00000000000..f0ba53566bc --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/characteristic-facet.js @@ -0,0 +1,37 @@ +define([ + 'coding-rules/facets/base-facet' +], function (BaseFacet) { + + var $ = jQuery; + + return BaseFacet.extend({ + + getValues: function () { + var values = _.map(this.options.app.characteristics, function (value, key) { + return { + label: value, + val: key + }; + }); + return _.sortBy(values, 'label'); + }, + + toggleFacet: function (e) { + var obj = {}, + property = this.model.get('property'); + if ($(e.currentTarget).is('.active')) { + obj[property] = null; + } else { + obj[property] = $(e.currentTarget).data('value'); + } + this.options.app.state.updateFilter(obj); + }, + + serializeData: function () { + return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), { + values: this.getValues() + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/custom-labels-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/custom-labels-facet.js new file mode 100644 index 00000000000..af54a48b2d2 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/custom-labels-facet.js @@ -0,0 +1,28 @@ +define([ + 'coding-rules/facets/base-facet' +], function (BaseFacet) { + + return BaseFacet.extend({ + + getLabelsSource: function () { + return []; + }, + + getValues: function () { + var that = this, + labels = that.getLabelsSource(); + return this.model.getValues().map(function (item) { + return _.extend(item, { + label: labels[item.val] + }); + }); + }, + + serializeData: function () { + return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), { + values: this.getValues() + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/language-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/language-facet.js new file mode 100644 index 00000000000..6a89c42d93a --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/language-facet.js @@ -0,0 +1,13 @@ +define([ + 'coding-rules/facets/custom-labels-facet' +], function (CustomLabelsFacet) { + + return CustomLabelsFacet.extend({ + + getLabelsSource: function () { + return this.options.app.languages; + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/quality-profile-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/quality-profile-facet.js new file mode 100644 index 00000000000..1e90e2bacca --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/quality-profile-facet.js @@ -0,0 +1,41 @@ +define([ + 'coding-rules/facets/base-facet' +], function (BaseFacet) { + + var $ = jQuery; + + return BaseFacet.extend({ + + getValues: function () { + var that = this, + values = this.options.app.qualityProfiles.map(function (profile) { + return { + label: profile.name, + extra: that.options.app.languages[profile.lang], + val: profile.key + }; + }); + return _.sortBy(values, 'label'); + }, + + toggleFacet: function (e) { + var obj = {}, + property = this.model.get('property'); + if ($(e.currentTarget).is('.active')) { + obj.activation = null; + obj[property] = null; + } else { + obj.activation = true; + obj[property] = $(e.currentTarget).data('value'); + } + this.options.app.state.updateFilter(obj); + }, + + serializeData: function () { + return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), { + values: this.getValues() + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/repository-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/repository-facet.js new file mode 100644 index 00000000000..5bf8361f6e1 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/repository-facet.js @@ -0,0 +1,27 @@ +define([ + 'coding-rules/facets/custom-labels-facet' +], function (CustomLabelsFacet) { + + return CustomLabelsFacet.extend({ + + getLabelsSource: function () { + var repos = this.options.app.repositories; + return _.object(_.pluck(repos, 'key'), _.pluck(repos, 'name')); + }, + + getValues: function () { + var that = this, + values = CustomLabelsFacet.prototype.getValues.apply(this, arguments); + return values.map(function (value) { + var repo = _.findWhere(that.options.app.repositories, { key: value.val }); + if (repo != null) { + var langName = that.options.app.languages[repo.language]; + _.extend(value, { extra: langName }); + } + return value; + }); + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/severity-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/severity-facet.js new file mode 100644 index 00000000000..133cc18c3a6 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/severity-facet.js @@ -0,0 +1,30 @@ +define([ + 'coding-rules/facets/base-facet', + 'templates/coding-rules' +], function (BaseFacet, Templates) { + + return BaseFacet.extend({ + template: Templates['coding-rules-severity-facet'], + severities: ['BLOCKER', 'MINOR', 'CRITICAL', 'INFO', 'MAJOR'], + + sortValues: function (values) { + var order = this.severities; + return _.sortBy(values, function (v) { + return order.indexOf(v.val); + }); + }, + + getValues: function () { + return this.severities.map(function (s) { + return { val: s }; + }); + }, + + serializeData: function () { + return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), { + values: this.sortValues(this.getValues()) + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/facets/status-facet.js b/server/sonar-web/src/main/js/coding-rules/facets/status-facet.js new file mode 100644 index 00000000000..3429f1a5147 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/facets/status-facet.js @@ -0,0 +1,23 @@ +define([ + 'coding-rules/facets/base-facet' +], function (BaseFacet) { + + return BaseFacet.extend({ + + getValues: function () { + return ['BETA', 'DEPRECATED', 'READY'].map(function (s) { + return { + label: t('rules.status', s.toLowerCase()), + val: s + }; + }); + }, + + serializeData: function () { + return _.extend(BaseFacet.prototype.serializeData.apply(this, arguments), { + values: this.sortValues(this.getValues()) + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/filters-view.js b/server/sonar-web/src/main/js/coding-rules/filters-view.js new file mode 100644 index 00000000000..9c2de652b4a --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/filters-view.js @@ -0,0 +1,18 @@ +define([ + 'backbone.marionette', + 'templates/coding-rules' +], function (Marionette, Templates) { + + return Marionette.ItemView.extend({ + template: Templates['coding-rules-filters'], + + events: { + 'click .js-new-search': 'newSearch' + }, + + newSearch: function () { + this.options.app.controller.newSearch(); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/layout.js b/server/sonar-web/src/main/js/coding-rules/layout.js new file mode 100644 index 00000000000..f6386fa375a --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/layout.js @@ -0,0 +1,58 @@ +define([ + 'backbone.marionette', + 'templates/coding-rules' +], function (Marionette, Templates) { + + var $ = jQuery; + + return Marionette.Layout.extend({ + template: Templates['coding-rules-layout'], + topOffset: 30, + + regions: { + filtersRegion: '.search-navigator-filters', + facetsRegion: '.search-navigator-facets', + workspaceHeaderRegion: '.search-navigator-workspace-header', + workspaceListRegion: '.search-navigator-workspace-list', + workspaceDetailsRegion: '.search-navigator-workspace-details' + }, + + initialize: function () { + var that = this; + $(window).on('scroll.search-navigator-layout', function () { + that.onScroll(); + }); + }, + + onClose: function () { + $(window).off('scroll.search-navigator-layout'); + }, + + onRender: function () { + this.$('.search-navigator-side').isolatedScroll(); + }, + + onScroll: function () { + var scrollTop = $(window).scrollTop(); + $('.search-navigator').toggleClass('sticky', scrollTop >= this.topOffset); + this.$('.search-navigator-side').css({ + top: Math.max(0, Math.min(this.topOffset - scrollTop, this.topOffset)) + }); + }, + + showDetails: function () { + this.scroll = $(window).scrollTop(); + $('.search-navigator').addClass('search-navigator-extended-view'); + }, + + + hideDetails: function () { + $('.search-navigator').removeClass('search-navigator-extended-view'); + if (this.scroll != null) { + $(window).scrollTop(this.scroll); + } + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/models/rule.js b/server/sonar-web/src/main/js/coding-rules/models/rule.js new file mode 100644 index 00000000000..78c1804a21d --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/models/rule.js @@ -0,0 +1,9 @@ +define([ + 'backbone' +], function (Backbone) { + + return Backbone.Model.extend({ + idAttribute: 'key' + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/models/rules.js b/server/sonar-web/src/main/js/coding-rules/models/rules.js new file mode 100644 index 00000000000..ea0c3577a2d --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/models/rules.js @@ -0,0 +1,20 @@ +define([ + 'backbone', + 'coding-rules/models/rule' +], function (Backbone, Rule) { + + return Backbone.Collection.extend({ + model: Rule, + + parseRules: function (r) { + return r.rules; + }, + + setIndex: function () { + this.forEach(function (rule, index) { + rule.set({ index: index }); + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/models/state.js b/server/sonar-web/src/main/js/coding-rules/models/state.js new file mode 100644 index 00000000000..c69164b95a4 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/models/state.js @@ -0,0 +1,15 @@ +define([ + 'components/navigator/models/state' +], function (State) { + + return State.extend({ + defaults: { + page: 1, + maxResultsReached: false, + query: {}, + facets: [] + } + }); + +}); + diff --git a/server/sonar-web/src/main/js/coding-rules/rule-details-view.js b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js new file mode 100644 index 00000000000..202e1698dfd --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js @@ -0,0 +1,56 @@ +define([ + 'backbone.marionette', + 'templates/coding-rules' +], function (Marionette, Templates) { + + return Marionette.ItemView.extend({ + template: Templates['coding-rules-rule-details'], + + modelEvents: { + 'change': 'render' + }, + + initialize: function () { + this.bindShortcuts(); + }, + + onClose: function () { + this.unbindShortcuts(); + }, + + bindShortcuts: function () { + var that = this; + key('up', 'details', function () { + that.options.app.controller.selectPrev(); + that.options.app.controller.showDetailsForSelected(); + return false; + }); + key('down', 'details', function () { + that.options.app.controller.selectNext(); + that.options.app.controller.showDetailsForSelected(); + return false; + }); + key('left', 'details', function () { + that.options.app.controller.hideDetails(); + return false; + }); + }, + + unbindShortcuts: function () { + key.deleteScope('details'); + }, + + serializeData: function () { + var isManual = (this.options.app.manualRepository().key === this.model.get('repo')); + + return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { + language: this.options.app.languages[this.model.get('lang')], + repository: _.findWhere(this.options.app.repositories, { key: this.model.get('repo') }).name, + isManual: isManual, + subCharacteristic: this.options.app.getSubCharacteristicName(this.model.get('debtSubChar')), + allTags: _.union(this.model.get('sysTags'), this.model.get('tags')) + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/workspace-header-view.js b/server/sonar-web/src/main/js/coding-rules/workspace-header-view.js new file mode 100644 index 00000000000..fae2372a8dc --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/workspace-header-view.js @@ -0,0 +1,20 @@ +define([ + 'components/navigator/workspace-header-view', + 'templates/coding-rules' +], function (WorkspaceHeaderView, Templates) { + + return WorkspaceHeaderView.extend({ + template: Templates['coding-rules-workspace-header'], + + events: function () { + return _.extend(WorkspaceHeaderView.prototype.events.apply(this, arguments), { + 'click .js-back': 'onBackClick' + }); + }, + + onBackClick: function () { + this.options.app.controller.hideDetails(); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js b/server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js new file mode 100644 index 00000000000..890f05d2af9 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/workspace-list-item-view.js @@ -0,0 +1,28 @@ +define([ + 'components/navigator/workspace-list-item-view', + 'templates/coding-rules' +], function (WorkspaceListItemView, Templates) { + + return WorkspaceListItemView.extend({ + className: 'coding-rule', + template: Templates['coding-rules-workspace-list-item'], + + modelEvents: { + 'change': 'render' + }, + + events: { + 'click': 'selectCurrent', + 'click .js-rule': 'openRule' + }, + + selectCurrent: function () { + this.options.app.state.set({ selectedIndex: this.model.get('index') }); + }, + + openRule: function () { + this.options.app.controller.showDetails(this.model); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/coding-rules/workspace-list-view.js b/server/sonar-web/src/main/js/coding-rules/workspace-list-view.js new file mode 100644 index 00000000000..56d193d7398 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/workspace-list-view.js @@ -0,0 +1,49 @@ +define([ + 'components/navigator/workspace-list-view', + 'coding-rules/workspace-list-item-view', + 'templates/coding-rules' +], function (WorkspaceListView, WorkspaceListItemView, Templates) { + + var $ = jQuery; + + return WorkspaceListView.extend({ + template: Templates['coding-rules-workspace-list'], + itemView: WorkspaceListItemView, + itemViewContainer: '.js-list', + + events: function () { + return { + 'click .js-tag': 'onTagClick', + 'click .js-lang': 'onLangClick' + }; + }, + + bindShortcuts: function () { + WorkspaceListView.prototype.bindShortcuts.apply(this, arguments); + var that = this; + key('right', 'list', function () { + that.options.app.controller.showDetailsForSelected(); + return false; + }); + }, + + onTagClick: function (e) { + var tag = $(e.currentTarget).data('tag'); + this.selectTag(tag); + }, + + onLangClick: function (e) { + var lang = $(e.currentTarget).data('lang'); + this.selectLang(lang); + }, + + selectTag: function (tag) { + this.options.app.state.setQuery({ tags: tag }); + }, + + selectLang: function (lang) { + this.options.app.state.setQuery({ languages: lang }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/controller.js b/server/sonar-web/src/main/js/components/navigator/controller.js new file mode 100644 index 00000000000..d1ae597ce0a --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/controller.js @@ -0,0 +1,142 @@ +define([ + 'backbone.marionette' +], function (Marionette) { + + return Marionette.Controller.extend({ + pageSize: 50, + allFacets: [], + facetsFromServer: [], + transform: {}, + + initialize: function (options) { + this.app = options.app; + this.listenTo(options.app.state, 'change:query', this.fetchList); + }, + + _allFacets: function () { + return this.allFacets.map(function (facet) { + return {property: facet}; + }); + }, + + _enabledFacets: function () { + var that = this, + facets = this.options.app.state.get('facets'), + criteria = Object.keys(this.options.app.state.get('query')); + facets = facets.concat(criteria); + facets = facets.map(function (facet) { + return that.transform[facet] != null ? that.transform[facet] : facet; + }); + return facets.filter(function (facet) { + return that.allFacets.indexOf(facet) !== -1; + }); + }, + + _facetsFromServer: function () { + var that = this, + facets = this._enabledFacets(); + return facets.filter(function (facet) { + return that.facetsFromServer.indexOf(facet) !== -1; + }); + }, + + fetchList: function () { + + }, + + fetchNextPage: function () { + this.options.app.state.nextPage(); + return this.fetchList(false); + }, + + enableFacet: function (id) { + var facet = this.options.app.facets.get(id); + if (facet.has('values') || this.facetsFromServer.indexOf(id) === -1) { + facet.set({enabled: true}); + } else { + var p = window.process.addBackgroundProcess(); + this.requestFacet(id) + .done(function () { + facet.set({enabled: true}); + window.process.finishBackgroundProcess(p); + }) + .fail(function () { + window.process.failBackgroundProcess(p); + }); + } + }, + + disableFacet: function (id) { + var facet = this.options.app.facets.get(id); + facet.set({enabled: false}); + this.options.app.facetsView.children.findByModel(facet).disable(); + }, + + toggleFacet: function (id) { + var facet = this.options.app.facets.get(id); + if (facet.get('enabled')) { + this.disableFacet(id); + } else { + this.enableFacet(id); + } + }, + + enableFacets: function (facets) { + facets.forEach(this.enableFacet, this); + }, + + newSearch: function () { + this.options.app.state.setQuery({}); + }, + + parseQuery: function (query, separator) { + separator = separator || '|'; + var q = {}; + (query || '').split(separator).forEach(function (t) { + var tokens = t.split('='); + if (tokens[0] && tokens[1] != null) { + q[tokens[0]] = decodeURIComponent(tokens[1]); + } + }); + return q; + }, + + getQuery: function (separator) { + separator = separator || '|'; + var filter = this.options.app.state.get('query'), + route = []; + _.map(filter, function (value, property) { + route.push('' + property + '=' + encodeURIComponent(value)); + }); + return route.join(separator); + }, + + getRoute: function (separator) { + separator = separator || '|'; + return this.getQuery(separator); + }, + + selectNext: function () { + var index = this.options.app.state.get('selectedIndex') + 1; + if (index < this.options.app.list.length) { + this.options.app.state.set({ selectedIndex: index }); + } else { + if (!this.options.app.state.get('maxResultsReached')) { + var that = this; + this.fetchNextPage().done(function () { + that.options.app.state.set({ selectedIndex: index }); + }); + } + } + }, + + selectPrev: function () { + var index = this.options.app.state.get('selectedIndex') - 1; + if (index >= 0) { + this.options.app.state.set({ selectedIndex: index }); + } + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/facets-view.js b/server/sonar-web/src/main/js/components/navigator/facets-view.js new file mode 100644 index 00000000000..0d3f9102833 --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/facets-view.js @@ -0,0 +1,37 @@ +define([ + 'backbone.marionette', + 'components/navigator/facets/base-facet' +], function (Marionette, BaseFacet) { + + return Marionette.CollectionView.extend({ + className: 'search-navigator-facets-list', + + itemViewOptions: function () { + return { + app: this.options.app + }; + }, + + getItemView: function () { + return BaseFacet; + }, + + collectionEvents: function () { + return { + 'change:enabled': 'updateState' + }; + }, + + updateState: function () { + var enabledFacets = this.collection.filter(function (model) { + return model.get('enabled'); + }), + enabledFacetIds = enabledFacets.map(function (model) { + return model.id; + }); + this.options.app.state.set({facets: enabledFacetIds}); + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/facets/base-facet.js b/server/sonar-web/src/main/js/components/navigator/facets/base-facet.js new file mode 100644 index 00000000000..c2c894ab45a --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/facets/base-facet.js @@ -0,0 +1,76 @@ +define([ + 'backbone.marionette' +], function (Marionette) { + + var $ = jQuery; + + return Marionette.ItemView.extend({ + className: 'search-navigator-facet-box', + + modelEvents: function () { + return { + 'change': 'render' + }; + }, + + events: function () { + return { + 'click .js-facet-toggle': 'toggle', + 'click .js-facet': 'toggleFacet' + }; + }, + + onRender: function () { + this.$el.toggleClass('search-navigator-facet-box-collapsed', !this.model.get('enabled')); + var that = this, + property = this.model.get('property'), + value = this.options.app.state.get('query')[property]; + if (typeof value === 'string') { + value.split(',').forEach(function (s) { + var facet = that.$('.js-facet').filter('[data-value="' + s + '"]'); + if (facet.length > 0) { + facet.addClass('active'); + } + }); + } + }, + + toggle: function () { + this.options.app.controller.toggleFacet(this.model.id); + }, + + getValue: function () { + return this.$('.js-facet.active').map(function () { + return $(this).data('value'); + }).get().join(); + }, + + toggleFacet: function (e) { + $(e.currentTarget).toggleClass('active'); + var property = this.model.get('property'), + obj = {}; + obj[property] = this.getValue(); + this.options.app.state.updateFilter(obj); + }, + + disable: function () { + var property = this.model.get('property'), + obj = {}; + obj[property] = null; + this.options.app.state.updateFilter(obj); + }, + + sortValues: function (values) { + return _.sortBy(values, function (v) { + return -v.count; + }); + }, + + serializeData: function () { + return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { + values: this.sortValues(this.model.getValues()) + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/models/facet.js b/server/sonar-web/src/main/js/components/navigator/models/facet.js new file mode 100644 index 00000000000..7d15da0507a --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/models/facet.js @@ -0,0 +1,22 @@ +define([ + 'backbone' +], function (Backbone) { + + return Backbone.Model.extend({ + idAttribute: 'property', + + defaults: { + enabled: false + }, + + getValues: function () { + return this.get('values') || []; + }, + + toggle: function () { + var enabled = this.get('enabled'); + this.set({ enabled: !enabled }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/models/facets.js b/server/sonar-web/src/main/js/components/navigator/models/facets.js new file mode 100644 index 00000000000..88929deb8da --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/models/facets.js @@ -0,0 +1,10 @@ +define([ + 'backbone', + 'components/navigator/models/facet' +], function (Backbone, Facet) { + + return Backbone.Collection.extend({ + model: Facet + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/models/state.js b/server/sonar-web/src/main/js/components/navigator/models/state.js new file mode 100644 index 00000000000..8a4f2ff669c --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/models/state.js @@ -0,0 +1,52 @@ +define([ + 'backbone' +], function (Backbone) { + + return Backbone.Model.extend({ + defaults: { + page: 1, + maxResultsReached: false, + query: {}, + facets: [] + }, + + nextPage: function () { + var page = this.get('page'); + this.set({ page: page + 1 }); + }, + + clearQuery: function (query) { + var q = {}; + Object.keys(query).forEach(function (key) { + if (query[key]) { + q[key] = query[key]; + } + }); + return q; + }, + + _areQueriesEqual: function (a, b) { + var equal = Object.keys(a).length === Object.keys(b).length; + Object.keys(a).forEach(function (key) { + equal = equal && a[key] === b[key]; + }); + return equal; + }, + + updateFilter: function (obj) { + var oldQuery = this.get('query'), + query = _.extend({}, oldQuery, obj); + query = this.clearQuery(query); + if (!this._areQueriesEqual(oldQuery, query)) { + this.setQuery(query); + } + }, + + setQuery: function (query) { + this.set({ query: query }, { silent: true }); + this.set({ changed: true }); + this.trigger('change:query'); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/router.js b/server/sonar-web/src/main/js/components/navigator/router.js new file mode 100644 index 00000000000..8792dd519c7 --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/router.js @@ -0,0 +1,29 @@ +define([ + 'backbone' +], function (Backbone) { + + return Backbone.Router.extend({ + routeSeparator: '|', + + routes: { + '': 'index', + ':query': 'index' + }, + + initialize: function (options) { + this.options = options; + this.listenTo(this.options.app.state, 'change:query', this.updateRoute); + }, + + index: function (query) { + query = this.options.app.controller.parseQuery(query); + this.options.app.state.setQuery(query); + }, + + updateRoute: function () { + var route = this.options.app.controller.getRoute(); + this.navigate(route); + } + }); + +}); 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 new file mode 100644 index 00000000000..aec6efa6284 --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/workspace-header-view.js @@ -0,0 +1,49 @@ +define([ + 'backbone.marionette' +], function (Marionette) { + + return Marionette.ItemView.extend({ + + collectionEvents: function () { + return { + 'all': 'render' + }; + }, + + events: function () { + return { + 'click .js-bulk-change': 'bulkChange', + 'click .js-reload': 'reload', + 'click .js-next': 'selectNext', + 'click .js-prev': 'selectPrev' + }; + }, + + initialize: function (options) { + this.listenTo(options.app.state, 'change', this.render); + }, + + bulkChange: function () { + + }, + + reload: function () { + this.options.app.controller.fetchList(); + }, + + selectNext: function () { + this.options.app.controller.selectNext(); + }, + + selectPrev: function () { + this.options.app.controller.selectPrev(); + }, + + serializeData: function () { + return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { + state: this.options.app.state.toJSON() + }); + } + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-list-item-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-list-item-view.js new file mode 100644 index 00000000000..b4bb669303a --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/workspace-list-item-view.js @@ -0,0 +1,26 @@ +define([ + 'backbone.marionette' +], function (Marionette) { + + return Marionette.ItemView.extend({ + + initialize: function (options) { + this.listenTo(options.app.state, 'change:selectedIndex', this.select); + }, + + onRender: function () { + this.select(); + }, + + select: function () { + var selected = this.model.get('index') === this.options.app.state.get('selectedIndex'); + this.$el.toggleClass('selected', selected); + }, + + selectCurrent: function () { + this.options.app.state.set({ selectedIndex: this.model.get('index') }); + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js new file mode 100644 index 00000000000..2c9ef0def7d --- /dev/null +++ b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js @@ -0,0 +1,112 @@ +define([ + 'backbone.marionette' +], function (Marionette) { + + var $ = jQuery; + + return Marionette.CompositeView.extend({ + + ui: { + loadMore: '.js-more' + }, + + itemViewOptions: function () { + return { + app: this.options.app + }; + }, + + collectionEvents: { + 'reset': 'scrollToTop' + }, + + initialize: function (options) { + this.loadMoreThrottled = _.throttle(this.loadMore, 1000, {trailing: false}); + this.listenTo(options.app.state, 'change:maxResultsReached', this.toggleLoadMore); + this.listenTo(options.app.state, 'change:selectedIndex', this.scrollTo); + this.bindShortcuts(); + }, + + onClose: function () { + this.unbindScrollEvents(); + this.unbindShortcuts(); + }, + + toggleLoadMore: function () { + this.ui.loadMore.toggle(!this.options.app.state.get('maxResultsReached')); + }, + + bindScrollEvents: function () { + var that = this; + $(window).on('scroll.workspace-list-view', function () { + that.onScroll(); + }); + }, + + unbindScrollEvents: function () { + $(window).off('scroll.workspace-list-view'); + }, + + bindShortcuts: function () { + var that = this; + key('up', 'list', function () { + that.options.app.controller.selectPrev(); + return false; + }); + + key('down', 'list', function () { + that.options.app.controller.selectNext(); + return false; + }); + }, + + loadMore: function () { + if (!this.options.app.state.get('maxResultsReached')) { + var that = this; + this.unbindScrollEvents(); + this.options.app.controller.fetchNextPage().done(function () { + that.bindScrollEvents(); + }); + } + }, + + disablePointerEvents: function () { + clearTimeout(this.scrollTimer); + $('body').addClass('disabled-pointer-events'); + this.scrollTimer = setTimeout(function () { + $('body').removeClass('disabled-pointer-events'); + }, 250); + }, + + onScroll: function () { + this.disablePointerEvents(); + if ($(window).scrollTop() + $(window).height() >= this.ui.loadMore.offset().top) { + this.loadMoreThrottled(); + } + }, + + scrollToTop: function () { + this.$el.scrollParent().scrollTop(0); + }, + + scrollTo: function () { + var selected = this.collection.at(this.options.app.state.get('selectedIndex')); + if (selected == null) { + return; + } + var selectedView = this.children.findByModel(selected), + viewTop = selectedView.$el.offset().top, + viewBottom = selectedView.$el.offset().top + selectedView.$el.outerHeight(), + windowTop = $(window).scrollTop(), + windowBottom = windowTop + $(window).height(); + if (viewTop < windowTop) { + $(window).scrollTop(viewTop); + } + if (viewBottom > windowBottom) { + $(window).scrollTop($(window).scrollTop() - windowBottom + viewBottom); + } + } + + }); + +}); diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/issues-page-spec.js b/server/sonar-web/src/main/js/tests/e2e/tests/issues-page-spec.js index 9e764d9e66d..56be033ca94 100644 --- a/server/sonar-web/src/main/js/tests/e2e/tests/issues-page-spec.js +++ b/server/sonar-web/src/main/js/tests/e2e/tests/issues-page-spec.js @@ -44,16 +44,16 @@ casper.test.begin(testName('Base'), function (test) { test.assertSelectorContains('.issue', '1 more branches need to be covered by unit tests to reach'); // Filters - test.assertExists('.js-issues-toggle-filters'); - test.assertExists('#issues-new-search'); - test.assertExists('#issues-filter-save-as'); + test.assertExists('.js-toggle-filters'); + test.assertExists('.js-new-search'); + test.assertExists('.js-filter-save-as'); // Workspace header test.assertSelectorContains('#issues-total', '4623'); - test.assertExists('.js-issues-prev'); - test.assertExists('.js-issues-next'); - test.assertExists('#issues-reload'); - test.assertExists('#issues-bulk-change'); + test.assertExists('.js-prev'); + test.assertExists('.js-next'); + test.assertExists('.js-reload'); + test.assertExists('.js-bulk-change'); }); }) diff --git a/server/sonar-web/src/main/js/tests/e2e/views/coding-rules.jade b/server/sonar-web/src/main/js/tests/e2e/views/coding-rules.jade index 32cfa03214d..cfdb7c9c011 100644 --- a/server/sonar-web/src/main/js/tests/e2e/views/coding-rules.jade +++ b/server/sonar-web/src/main/js/tests/e2e/views/coding-rules.jade @@ -3,7 +3,7 @@ extends ./layouts/main block header script(src='../js/require.js') script. - window.waitForMocks('/js/coding-rules/app.js'); + window.waitForMocks('/js/coding-rules-old/app.js'); block body #content diff --git a/server/sonar-web/src/main/less/components.less b/server/sonar-web/src/main/less/components.less index 28333bca7a8..622c74d61df 100644 --- a/server/sonar-web/src/main/less/components.less +++ b/server/sonar-web/src/main/less/components.less @@ -4,3 +4,5 @@ @import "components/modals"; @import "components/issues"; @import "components/measures"; +@import "components/rules"; +@import "components/search-navigator"; diff --git a/server/sonar-web/src/main/less/components/rules.less b/server/sonar-web/src/main/less/components/rules.less new file mode 100644 index 00000000000..affe5c40766 --- /dev/null +++ b/server/sonar-web/src/main/less/components/rules.less @@ -0,0 +1,59 @@ +@import (reference) "../variables"; +@import (reference) "../mixins"; +@import (reference) "../ui"; + +@leftPadding: 10px; +@rightPadding: 10px; +@topPadding: 8px; +@bottomPadding: 8px; +@lineHeight: @baseFontSize * 1.5; + +.coding-rule { + padding: @topPadding @rightPadding @bottomPadding @topPadding; + border: 1px solid transparent; + background-color: #fff; + + &.selected { + border-color: @blue !important; + } +} + +.coding-rule + .coding-rule { + border-top-color: @barBorderColor; +} + +.coding-rule.selected + .coding-rule { + border-top-color: transparent; +} + +.coding-rule-inner { + .justify; + margin-bottom: -16px; +} + +.coding-rule-title { + display: inline-block; + vertical-align: baseline; + line-height: @lineHeight; + font-size: @baseFontSize; +} + +.coding-rule-meta { + display: inline-block; + vertical-align: baseline; + line-height: @lineHeight; + font-size: @smallFontSize; + + .icon-tags:before { + color: @secondFontColor; + font-size: @smallFontSize; + } + + .js-tag:after { + content: ","; + } + + .js-tag:last-child:after { + content: ""; + } +} diff --git a/server/sonar-web/src/main/less/components/search-navigator.less b/server/sonar-web/src/main/less/components/search-navigator.less new file mode 100644 index 00000000000..e3ea4d51e1b --- /dev/null +++ b/server/sonar-web/src/main/less/components/search-navigator.less @@ -0,0 +1,324 @@ +@import (reference) "../variables"; +@import (reference) "../mixins"; +@import (reference) "../ui"; + +@sideWidth: 300px; + +.search-navigator { + + &.sticky { + + .search-navigator-workspace-header { + position: fixed; + z-index: 4; + top: 0; + left: @sideWidth; + right: 0px; + } + + .search-navigator-workspace-list { + padding-top: 22px + 5px + 5px + 1px + 10px; + } + + .search-navigator-side { + position: fixed; + z-index: 4; + top: 0; + bottom: 0; + overflow-y: auto; + } + + } +} + +.search-navigator-side { + position: fixed; + z-index: 100; + width: @sideWidth; + top: 30px; left: 0; bottom: 0; + .box-sizing(border-box); + background-color: @barBorderColor; + overflow-x: hidden; +} + +.search-navigator-facet-box { + border-top: 1px solid @barBorderColor; + background-color: @barBackgroundColor; + font-size: @baseFontSize; +} + +.search-navigator-facet-box-collapsed { + background-color: transparent; + + .search-navigator-facet-list, + .search-navigator-facet-container { + display: none; + } + + .search-navigator-facet-header { + color: @secondFontColor; + font-weight: 400; + + &:hover { color: @blue; } + } +} + +.search-navigator-facet { + position: relative; + width: 100%; + margin: 0 0 1px 0; + border-color: transparent; + .box-sizing(border-box); + background-color: @barBackgroundColor; + white-space: normal; + overflow-x: hidden; + + .facet-name { + white-space: nowrap; + background-color: @barBackgroundColor; + color: @baseFontColor; + } + + .facet-stat { + position: absolute; + top: 0; right: 0; + padding: 4px 5px; + border: none; + background-color: @barBackgroundColor; + + &:before { + content: " "; + position: absolute; + top: 0; bottom: 0; right: 100%; + width: 10px; + background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%); + } + } + + &.active .facet-stat:before { + background-image: linear-gradient(to right, fade(@lightBlue, 0%), @lightBlue 75%); + } +} + +.search-navigator-facet-half { + width: 45%; + + &:nth-child(odd) { + margin-right: 10%; + } +} + +.search-navigator-facet-header { + display: block; + padding: 6px 10px; + border-bottom: none; + color: @baseFontColor; + font-weight: 500; +} + +.search-navigator-facet-list { + margin: 0 0 0 0; + padding: 0 10px 10px; + font-size: 0; +} + +.search-navigator-facet-list-align-right { + + .facet-name { + float: right; + + &:before { + content: " "; + position: absolute; + top: 0; bottom: 0; left: 0; + width: 10px; + background-image: linear-gradient(to left, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%); + } + } + + .facet-stat:before { + display: none; + } + + .facet.active .facet-name:before { + background-image: linear-gradient(to left, fade(@lightBlue, 0%), @lightBlue 75%); + } + +} + +.search-navigator-facet-container { + margin-top: 6px; + padding: 0 10px 16px; +} + +.search-navigator-facet-custom-value { + padding: 0 0 5px; + font-size: @baseFontSize; +} + +.search-navigator-facet-input { + width: @sideWidth * 0.4; +} + +.search-navigator-filters { + position: relative; + .clearfix; + padding: 5px 10px; + background-color: @barBackgroundColor; +} + +.search-navigator-filters-selected { + margin-bottom: 5px; + + .search-navigator-filters-header { + float: none; + } + + .search-navigator-filters-actions { + float: none; + margin-top: 5px; + } +} + +.search-navigator-filters-list { + display: none; + position: absolute; + z-index: 6; + top: 31px; + left: 0; + right: 10px; + margin-bottom: 8px; + padding: 5px 10px; + border: 1px solid #e8e8e8; + .box-sizing(border-box); + line-height: 1.5; + background-color: #fff; + box-shadow: @defaultShadow; +} + +.search-navigator-filters-filter { + +} + +.search-navigator-filters-header { + float: left; + line-height: 22px; +} + +.search-navigator-filters-name { + vertical-align: top; + font-size: @bigFontSize; +} + +.search-navigator-filters-description { + margin: 4px 0; + font-size: @smallFontSize; + font-style: italic; +} + +.search-navigator-filters-show-list { + margin-right: 4px; + border-bottom: none; + color: @baseFontColor; + font-size: @iconSmallFontSize; +} + +.search-navigator-filters-actions { + float: right; +} + +.search-navigator-filters-manage { + display: inline-block; + margin-top: 4px; + border-bottom: none; +} + +.search-navigator-workspace { + padding-left: @sideWidth; +} + +.search-navigator-workspace-header { + position: relative; + margin-bottom: 10px; + padding: 5px 0; + line-height: 22px; + border-bottom: 1px solid @barBorderColor; + background-color: @barBackgroundColor; + font-size: @smallFontSize; + + .button-group, + .button-group > button, + .button-group > .button { + vertical-align: top; + } +} + +.search-navigator-header-component { + margin-left: 10px; + white-space: nowrap; +} + +.search-navigator-header-actions { + position: absolute; + top: 0; + right: 0; + padding: 5px 10px; + background-color: @barBackgroundColor; + font-size: 0; + white-space: nowrap; + + &:before { + content: " "; + position: absolute; + top: 0; bottom: 0; right: 100%; + width: 10px; + background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%); + } +} + +.search-navigator-header-pagination { + display: inline-block; + vertical-align: top; + margin-right: 20px; + font-size: @smallFontSize; +} + +.search-navigator-header-buttons { + vertical-align: top; +} + +.search-navigator-workspace-list { + padding: 0 5px; + + .issue { + max-width: none; + } +} + +.search-navigator-workspace-details { + display: none; + padding: 0 10px; +} + +.search-navigator-workspace-list-more { + margin-top: 10px; + padding: 5px 10px; + text-align: center; +} + +.search-navigator-no-results { + padding-top: 10%; + color: @secondFontColor; + text-align: center; +} + +.search-navigator-extended-view { + + .search-navigator-workspace-list { + display: none; + } + + .search-navigator-workspace-details { + display: block; + } +} diff --git a/server/sonar-web/src/main/less/issues.less b/server/sonar-web/src/main/less/issues.less index 2948a304938..1bb3b601012 100644 --- a/server/sonar-web/src/main/less/issues.less +++ b/server/sonar-web/src/main/less/issues.less @@ -9,301 +9,14 @@ &.sticky { - .issues-workspace-header { - position: fixed; - z-index: 4; - top: 0; - left: @sideWidth; - right: 0px; - } - .issues-workspace-list, .issues-workspace-component-viewer { padding-top: 22px + 5px + 5px + 1px + 10px; } - .issues-side { - position: fixed; - z-index: 4; - top: 0; - bottom: 0; - overflow-y: auto; - } - - } -} - -.issues-side { - position: fixed; - z-index: 100; - width: @sideWidth; - top: 30px; left: 0; bottom: 0; - .box-sizing(border-box); - background-color: @barBorderColor; - overflow-x: hidden; -} - -.issues-facet-box { - border-top: 1px solid @barBorderColor; - background-color: @barBackgroundColor; - font-size: @baseFontSize; -} - -.issues-facet-box-collapsed { - background-color: transparent; - - .issues-facet-list, - .issues-facet-container { - display: none; - } - - .issues-facet-header { - color: @secondFontColor; - font-weight: 400; - - &:hover { color: @blue; } - } -} - -.issues-facet { - position: relative; - width: 100%; - margin: 0 0 1px 0; - border-color: transparent; - .box-sizing(border-box); - background-color: @barBackgroundColor; - white-space: normal; - overflow-x: hidden; - - .facet-name { - white-space: nowrap; - background-color: @barBackgroundColor; - color: @baseFontColor; - } - - .facet-stat { - position: absolute; - top: 0; right: 0; - padding: 4px 5px; - border: none; - background-color: @barBackgroundColor; - - &:before { - content: " "; - position: absolute; - top: 0; bottom: 0; right: 100%; - width: 10px; - background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%); - } - } - - &.active .facet-stat:before { - background-image: linear-gradient(to right, fade(@lightBlue, 0%), @lightBlue 75%); } } -.issues-facet-half { - width: 45%; - - &:nth-child(odd) { - margin-right: 10%; - } -} - -.issues-facet-header { - display: block; - padding: 6px 10px; - border-bottom: none; - color: @baseFontColor; - font-weight: 500; -} - -.issues-facet-list { - margin: 0 0 0 0; - padding: 0 10px 10px; - font-size: 0; -} - -.issues-facet-list-align-right { - - .facet-name { - float: right; - - &:before { - content: " "; - position: absolute; - top: 0; bottom: 0; left: 0; - width: 10px; - background-image: linear-gradient(to left, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%); - } - } - - .facet-stat:before { - display: none; - } - - .facet.active .facet-name:before { - background-image: linear-gradient(to left, fade(@lightBlue, 0%), @lightBlue 75%); - } - -} - -.issues-facet-container { - margin-top: 6px; - padding: 0 10px 16px; -} - -.issues-facet-custom-value { - padding: 0 0 5px; - font-size: @baseFontSize; -} - -.issues-facet-input { - width: @sideWidth * 0.4; -// .box-sizing(border-box); -} - -.issues-filters { - position: relative; - .clearfix; - padding: 5px 10px; - background-color: @barBackgroundColor; -} - -.issues-filters-selected { - margin-bottom: 5px; - - .issues-filters-header { - float: none; - } - - .issues-filters-actions { - float: none; - margin-top: 5px; - } -} - -.issues-filters-list { - display: none; - position: absolute; - z-index: 6; - top: 31px; - left: 0; - right: 10px; - margin-bottom: 8px; - padding: 5px 10px; - border: 1px solid #e8e8e8; - .box-sizing(border-box); - line-height: 1.5; - background-color: #fff; - box-shadow: @defaultShadow; -} - -.issues-filters-filter { - -} - -.issues-filters-header { - float: left; - line-height: 22px; -} - -.issues-filters-name { - vertical-align: top; - font-size: @bigFontSize; -} - -.issues-filters-description { - margin: 4px 0; - font-size: @smallFontSize; - font-style: italic; -} - -.issues-filters-show-list { - margin-right: 4px; - border-bottom: none; - color: @baseFontColor; - font-size: @iconSmallFontSize; -} - -.issues-filters-actions { - float: right; -} - -.issues-filters-manage { - display: inline-block; - margin-top: 4px; - border-bottom: none; -} - -.issues-workspace { - padding-left: @sideWidth; -} - -.issues-header { - position: relative; - margin-bottom: 10px; - padding: 5px 0; - line-height: 22px; - border-bottom: 1px solid @barBorderColor; - background-color: @barBackgroundColor; - font-size: @smallFontSize; - - .button-group, - .button-group > button, - .button-group > .button { - vertical-align: top; - } -} - -.issues-header-component { - margin-left: 10px; - white-space: nowrap; -} - -.issues-header-actions { - position: absolute; - top: 0; - right: 0; - padding: 5px 10px; - background-color: @barBackgroundColor; - font-size: 0; - white-space: nowrap; - - &:before { - content: " "; - position: absolute; - top: 0; bottom: 0; right: 100%; - width: 10px; - background-image: linear-gradient(to right, fade(@barBackgroundColor, 0%), @barBackgroundColor 75%); - } -} - -.issues-header-pagination { - display: inline-block; - vertical-align: top; - margin-right: 20px; - font-size: @smallFontSize; -} - -.issues-header-buttons { - vertical-align: top; -} - -.issues-workspace-list { - padding: 0 5px; - - .issue { - max-width: none; - } -} - -.issues-workspace-list-more { - margin-top: 10px; - padding: 5px 10px; - text-align: center; -} - .issues-workspace-list-component { line-height: 1.5; } @@ -344,7 +57,7 @@ .issues-extended-view { - .issues-workspace-list { + .search-navigator-workspace-list { display: none; } @@ -378,12 +91,6 @@ } -.issues-no-results { - padding-top: 10%; - color: @secondFontColor; - text-align: center; -} - .code-issue-modern { outline: 1px solid @barBorderColor; border-left: 2px solid transparent; diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_old_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_old_controller.rb new file mode 100644 index 00000000000..3011a79b876 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_old_controller.rb @@ -0,0 +1,30 @@ +# +# 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 CodingRulesOldController < ApplicationController + + SECTION=Navigation::SECTION_CODING_RULES_OLD + + # GET /coding_rules_old/index + def index + + end + +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/models/navigation.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/models/navigation.rb index 4b690d90178..fbe166a9cbb 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/models/navigation.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/models/navigation.rb @@ -36,4 +36,5 @@ class Navigation SECTION_QUALITY_PROFILES = Navigation.new('quality_profiles', false) SECTION_QUALITY_GATES = Navigation.new('quality_gates', false) SECTION_CODING_RULES = Navigation.new('coding_rules', false) + SECTION_CODING_RULES_OLD = Navigation.new('coding_rules_old', false) end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb index 0d190ef7d3c..3d13e30672a 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/index.html.erb @@ -3,6 +3,4 @@ <% end %> - +
    diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules_old/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules_old/index.html.erb new file mode 100644 index 00000000000..116f5fa0125 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules_old/index.html.erb @@ -0,0 +1,8 @@ +<% content_for :script do %> + +<% end %> + + + diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/search.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/search.html.erb index 3643c208073..5d8052da4dd 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/search.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/search.html.erb @@ -2,4 +2,4 @@ <% end %> -
    +
    diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb index fd4844050c6..e52d7018a19 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb @@ -22,7 +22,10 @@ <%= message('issues.page') -%>
  • - <%= message('coding_rules.page') -%> + NEW <%= message('coding_rules.page') -%> +
  • +
  • + <%= message('coding_rules.page') -%>
  • <%= message('quality_profiles.page') -%> 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 bf32d5f404a..1939732aa98 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1792,6 +1792,7 @@ coding_rules.found=Found coding_rules.inherits="{0}" inherits from "{1}" coding_rules.key=Key: coding_rules.manual_rule=Manual Rule +coding_rules.manual_rules=Manual Rules coding_rules.new_search=New Search coding_rules.no_results=No Coding Rules coding_rules.no_tags=No tags @@ -1809,6 +1810,7 @@ coding_rules.quality_profiles.template_caption=This rule template was activated coding_rules.quality_profile=Quality Profile coding_rules.reactivate=Reactivate coding_rules.reactivate.help=A rule with the same key has been previously deleted. Please reactivate the existing rule or modify the key to create a new rule. +coding_rules.return_to_list=Return to List coding_rules.remove_extended_description.confirm=Are you sure you want to remove the extended description? coding_rules.repository=Repository: coding_rules.revert_to_parent_definition=Revert to Parent Definition @@ -1847,6 +1849,14 @@ coding_rules.filters.template=Templates coding_rules.filters.template.is_template=Show Templates Only coding_rules.filters.template.is_not_template=Hide Templates +coding_rules.facet.languages=Language +coding_rules.facet.repositories=Repository +coding_rules.facet.tags=Tag +coding_rules.facet.qprofile=Quality Profile +coding_rules.facet.debt_characteristics=Characteristic +coding_rules.facet.severities=Severity +coding_rules.facet.statuses=Status + coding_rules.facets.languages=Languages coding_rules.facets.tags=Tags coding_rules.facets.repositories=Repositories