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'
'<%= 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'
]
--- /dev/null
+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()
--- /dev/null
+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('<i class="spinner"></i>')
+
+
+ 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
--- /dev/null
+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: '''
+ <p>
+ According to the Java Language Specification:
+ </p>
+
+ <pre>For compatibility with older versions of the Java SE platform,
+ the declaration of a method that returns an array is allowed to place (some or all of)
+ the empty bracket pairs that form the declaration of the array type after
+ the formal parameter list. This obsolescent syntax should not be used in new code.
+ </pre>
+
+ <p>The following code snippet illustrates this rule:</p>
+
+ <pre>public int getVector()[] { /* ... */ } // Non-Compliant
+
+ public int[] getVector() { /* ... */ } // Compliant
+
+ public int[] getMatrix()[] { /* ... */ } // Non-Compliant
+
+ public int[][] getMatrix() { /* ... */ } // Compliant
+ </pre>'''
+ extra: '''This note is here <b>only for test purposes</b>.'''
+ extraRaw: '''This note is here *only for test purposes*.'''
+
+ qualityProfiles: [
+ {
+ name: 'SonarWay'
+ key: 'sonarway'
+ severity: 'MINOR'
+ parameters: [
+ { key: 'someParameter', value: 8 }
+ { 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 <i>only for test purposes</i>.'''
+ extraRaw: '''This note is here *only for test purposes*.'''
+
+
+ # POST /api/codingrules/bulk_change
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/bulk_change"
+
+
+ # POST /api/codingrules/set_tags
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/set_tags"
+
+
+ # POST /api/codingrules/activate
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/activate"
+
+
+ # POST /api/codingrules/note
+ jQuery.mockjax
+ url: "#{baseUrl}/api/codingrules/note"
+ responseText: JSON.stringify
+ note:
+ username: 'Admin Admin'
+ html: '''<p>This note is here <b>only for test purposes</b>.</p>'''
+ raw: '''This note is here *only for test purposes*.'''
+ fCreationDate: 'less than a minute'
+
+
+ # GET /api/qualityprofiles/list
+ jQuery.mockjax
+ url: "#{baseUrl}/api/qualityprofiles/list"
+ responseText: JSON.stringify
+ more: false
+ results: [
+ { id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null },
+ { id: 'qp1', text: 'Quality Profile 1', category: 'Java', parent: 'sonarway' },
+ { id: 'qp2', text: 'Quality Profile 2', category: 'JavaScript', parent: 'sonarway' },
+ { id: 'qp3', text: 'Quality Profile 3', category: 'Java', parent: null },
+ ]
+
+
+ # GET /api/qualityprofiles/show
+ jQuery.mockjax
+ url: "#{baseUrl}/api/qualityprofiles/show"
+ responseText: JSON.stringify
+ qualityprofile:
+ id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null
+
--- /dev/null
+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()
--- /dev/null
+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
--- /dev/null
+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')
--- /dev/null
+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 '<i class="spinner"></i>'
+
+ 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()
--- /dev/null
+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 '<i class="spinner"></i>'
+
+ 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
+ "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{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
--- /dev/null
+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')
--- /dev/null
+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 '<i class="spinner"></i>'
+
+ 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
--- /dev/null
+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
--- /dev/null
+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'
--- /dev/null
+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
--- /dev/null
+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 '<i class="spinner"></i>'
+
+ 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 '<i class="spinner"></i>'
+ 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')
--- /dev/null
+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'
--- /dev/null
+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']
--- /dev/null
+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)
--- /dev/null
+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
--- /dev/null
+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 '<i class="spinner"></i>'
+
+ 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
+ "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
+
+
+ show: ->
+ @render()
+ @$el.dialog 'open'
+
+
+ hide: ->
+ @$el.dialog 'close'
+
+
+ serializeData: ->
+ _.extend super,
+ change: @model && @model.has 'key'
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/coding-rules-old'
+ 'common/popup'
+], (
+ Marionette
+ Templates
+ Popup
+) ->
+
+ $ = jQuery
+
+
+ class CodingRulesParameterPopupView extends Popup
+ template: Templates['coding-rules-parameter-popup']
--- /dev/null
+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 '<i class="spinner"></i>'
+
+ 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
+ "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{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'
--- /dev/null
+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()
--- /dev/null
+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()
--- /dev/null
+
+define [
+ 'coding-rules-old/views/filters/profile-dependent-filter-view'
+], (
+ ProfileDependentFilterView
+) ->
+
+ class ActiveSeveritiesFilterView extends ProfileDependentFilterView
+ tooltip: 'coding_rules.filters.active_severity.inactive'
--- /dev/null
+define [
+ 'navigator/filters/choice-filters'
+], (
+ ChoiceFilters
+) ->
+
+ class CharacteriticFilterView extends ChoiceFilters.ChoiceFilterView
+
+ initialize: ->
+ super
+ @choices.comparator = 'text'
+ @choices.sort()
--- /dev/null
+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()
--- /dev/null
+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()
--- /dev/null
+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()
--- /dev/null
+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')
--- /dev/null
+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', '');
--- /dev/null
+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()
--- /dev/null
+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
--- /dev/null
+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
+++ /dev/null
-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()
+++ /dev/null
-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('<i class="spinner"></i>')
-
-
- 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
+++ /dev/null
-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: '''
- <p>
- According to the Java Language Specification:
- </p>
-
- <pre>For compatibility with older versions of the Java SE platform,
- the declaration of a method that returns an array is allowed to place (some or all of)
- the empty bracket pairs that form the declaration of the array type after
- the formal parameter list. This obsolescent syntax should not be used in new code.
- </pre>
-
- <p>The following code snippet illustrates this rule:</p>
-
- <pre>public int getVector()[] { /* ... */ } // Non-Compliant
-
- public int[] getVector() { /* ... */ } // Compliant
-
- public int[] getMatrix()[] { /* ... */ } // Non-Compliant
-
- public int[][] getMatrix() { /* ... */ } // Compliant
- </pre>'''
- extra: '''This note is here <b>only for test purposes</b>.'''
- extraRaw: '''This note is here *only for test purposes*.'''
-
- qualityProfiles: [
- {
- name: 'SonarWay'
- key: 'sonarway'
- severity: 'MINOR'
- parameters: [
- { key: 'someParameter', value: 8 }
- { 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 <i>only for test purposes</i>.'''
- extraRaw: '''This note is here *only for test purposes*.'''
-
-
- # POST /api/codingrules/bulk_change
- jQuery.mockjax
- url: "#{baseUrl}/api/codingrules/bulk_change"
-
-
- # POST /api/codingrules/set_tags
- jQuery.mockjax
- url: "#{baseUrl}/api/codingrules/set_tags"
-
-
- # POST /api/codingrules/activate
- jQuery.mockjax
- url: "#{baseUrl}/api/codingrules/activate"
-
-
- # POST /api/codingrules/note
- jQuery.mockjax
- url: "#{baseUrl}/api/codingrules/note"
- responseText: JSON.stringify
- note:
- username: 'Admin Admin'
- html: '''<p>This note is here <b>only for test purposes</b>.</p>'''
- raw: '''This note is here *only for test purposes*.'''
- fCreationDate: 'less than a minute'
-
-
- # GET /api/qualityprofiles/list
- jQuery.mockjax
- url: "#{baseUrl}/api/qualityprofiles/list"
- responseText: JSON.stringify
- more: false
- results: [
- { id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null },
- { id: 'qp1', text: 'Quality Profile 1', category: 'Java', parent: 'sonarway' },
- { id: 'qp2', text: 'Quality Profile 2', category: 'JavaScript', parent: 'sonarway' },
- { id: 'qp3', text: 'Quality Profile 3', category: 'Java', parent: null },
- ]
-
-
- # GET /api/qualityprofiles/show
- jQuery.mockjax
- url: "#{baseUrl}/api/qualityprofiles/show"
- responseText: JSON.stringify
- qualityprofile:
- id: 'sonarway', text: 'Sonar Way', category: 'Java', parent: null
-
+++ /dev/null
-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()
+++ /dev/null
-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
+++ /dev/null
-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')
+++ /dev/null
-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 '<i class="spinner"></i>'
-
- 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()
+++ /dev/null
-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 '<i class="spinner"></i>'
-
- 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
- "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{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
+++ /dev/null
-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')
+++ /dev/null
-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 '<i class="spinner"></i>'
-
- 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
+++ /dev/null
-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
+++ /dev/null
-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'
+++ /dev/null
-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
+++ /dev/null
-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 '<i class="spinner"></i>'
-
- 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 '<i class="spinner"></i>'
- 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')
+++ /dev/null
-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'
+++ /dev/null
-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']
+++ /dev/null
-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)
+++ /dev/null
-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
+++ /dev/null
-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 '<i class="spinner"></i>'
-
- 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
- "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{state.text}"
-
-
- show: ->
- @render()
- @$el.dialog 'open'
-
-
- hide: ->
- @$el.dialog 'close'
-
-
- serializeData: ->
- _.extend super,
- change: @model && @model.has 'key'
+++ /dev/null
-define [
- 'backbone.marionette'
- 'templates/coding-rules'
- 'common/popup'
-], (
- Marionette
- Templates
- Popup
-) ->
-
- $ = jQuery
-
-
- class CodingRulesParameterPopupView extends Popup
- template: Templates['coding-rules-parameter-popup']
+++ /dev/null
-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 '<i class="spinner"></i>'
-
- 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
- "<i class='icon-severity-#{state.id.toLowerCase()}'></i> #{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'
+++ /dev/null
-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()
+++ /dev/null
-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()
+++ /dev/null
-
-define [
- 'coding-rules/views/filters/profile-dependent-filter-view'
-], (
- ProfileDependentFilterView
-) ->
-
- class ActiveSeveritiesFilterView extends ProfileDependentFilterView
- tooltip: 'coding_rules.filters.active_severity.inactive'
+++ /dev/null
-define [
- 'navigator/filters/choice-filters'
-], (
- ChoiceFilters
-) ->
-
- class CharacteriticFilterView extends ChoiceFilters.ChoiceFilterView
-
- initialize: ->
- super
- @choices.comparator = 'text'
- @choices.sort()
+++ /dev/null
-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()
+++ /dev/null
-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()
+++ /dev/null
-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()
+++ /dev/null
-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')
+++ /dev/null
-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', '');
+++ /dev/null
-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()
+++ /dev/null
-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
+++ /dev/null
-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
'issues/models/state'
'issues/layout'
'issues/models/issues'
- 'issues/models/facets'
+ 'components/navigator/models/facets'
'issues/models/filters'
'issues/controller'
App.addInitializer ->
@state = new State()
- @issues = new Issues()
+ @list = new Issues()
@facets = new Facets()
@filters = new Filters()
App.addInitializer ->
@issuesView = new WorkspaceListView
app: @
- collection: @issues
+ collection: @list
@layout.workspaceListRegion.show @issuesView
@issuesView.bindScrollEvents()
App.addInitializer ->
@workspaceHeaderView = new WorkspaceHeaderView
app: @
- collection: @issues
+ collection: @list
@layout.workspaceHeaderRegion.show @workspaceHeaderView
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', =>
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
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
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
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
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
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) ->
define [
- 'backbone.marionette'
+ 'components/navigator/controller'
'issues/component-viewer/main'
'issues/component-viewer/state'
], (
- Marionette
+ Controller
ComponentViewer
ComponentViewerState
$ = 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()
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
window.process.failBackgroundProcess fetchIssuesProcess
- fetchNextPage: ->
- @options.app.state.nextPage()
- @fetchIssues false
-
-
fetchFilters: ->
$.get "#{baseUrl}/api/issue_filters/app", (r) =>
@options.app.state.set
@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
@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}"
@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
define [
- 'backbone.marionette'
+ 'components/navigator/facets-view'
'issues/facets/base-facet'
'issues/facets/severity-facet'
'issues/facets/language-facet'
'issues/facets/issue-key-facet'
], (
- Marionette
+ FacetsView
+
BaseFacet
SeverityFacet
StatusFacet
IssueKeyFacet
) ->
- class extends Marionette.CollectionView
- className: 'issues-facets-list'
-
+ class extends FacetsView
getItemView: (model) ->
switch model.get 'property'
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
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) ->
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) ->
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
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()
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'
events: ->
_.extend super,
- 'change .js-issues-custom-value': 'addCustomValue'
+ 'change .js-custom-value': 'addCustomValue'
getUrl: ->
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
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) ->
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
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
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) ->
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) ->
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'
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) ->
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'
-
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: ->
@options.app.controller.applyFilter filter
else
@options.app.state.setQuery query
-
-
- updateRoute: ->
- route = @options.app.controller.getRoute()
- @navigate route
-
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: ->
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()
-
) ->
class extends Marionette.ItemView
- className: 'issues-no-results'
+ className: 'search-navigator-no-results'
template: ->
initialize: (options) ->
+ super
@listenTo options.app.state, 'change:selectedIndex', @select
onRender: ->
super
- @$el.addClass 'issue-navigate-right'
@select()
+ @$el.addClass 'issue-navigate-right'
select: ->
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
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'
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'
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
--- /dev/null
+<div class="navigator-actions-order">
+ {{#if sorting}}
+ {{t 'coding_rules.ordered_by'}} <strong>{{sorting.sortText}}</strong> {{#if sorting.asc}}<i class="icon-sort-asc"></i>{{else}}<i class="icon-sort-desc"></i>{{/if}}
+ {{else}}
+ {{t 'coding_rules.order'}}
+ {{/if}}
+</div>
+<ul class="navigator-actions-order-choices">
+ <li data-sort="" data-asc="">{{t 'coding_rules.sort.relevance'}}</li>
+ <li data-sort="createdAt" data-asc="true">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-asc"></i></li>
+ <li data-sort="createdAt" data-asc="false">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-desc"></i></li>
+ <li data-sort="name" data-asc="true">{{t 'coding_rules.sort.name'}} <i class="icon-sort-asc"></i></li>
+ <li data-sort="name" data-asc="false">{{t 'coding_rules.sort.name'}} <i class="icon-sort-desc"></i></li>
+</ul>
+<div class="navigator-actions-total">
+ {{t 'coding_rules.found'}}: <strong>{{paging.total}}</strong>
+ {{#if canWrite}}<a class="navigator-actions-bulk icon-bulk-change" title="{{t 'bulk_change'}}"></a>{{/if}}
+</div>
--- /dev/null
+{{! activation }}
+
+<a class="coding-rules-bulk-change-dropdown-link" data-action="activate">
+ {{t 'coding_rules.activate_in'}}…
+</a>
+
+{{#if allowActivateOnProfile}}
+ <a class="coding-rules-bulk-change-dropdown-link" data-action="activate" data-param="{{qualityProfile}}">
+ {{t 'coding_rules.activate_in'}} <strong>{{qualityProfileName}}</strong>
+ </a>
+{{/if}}
+
+
+
+{{! deactivation }}
+
+<a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate">
+ {{t 'coding_rules.deactivate_in'}}…
+</a>
+
+{{#if allowDeactivateOnProfile}}
+ <a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate" data-param="{{qualityProfile}}">
+ {{tp 'coding_rules.deactivate_in'}} <strong>{{qualityProfileName}}</strong>
+ </a>
+{{/if}}
--- /dev/null
+<form>
+ <div class="modal-head">
+ {{#eq action 'activate'}}
+ <h2>{{t 'coding_rules.activate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
+ {{/eq}}
+ {{#eq action 'deactivate'}}
+ <h2>{{t 'coding_rules.deactivate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
+ {{/eq}}
+ </div>
+
+ <div class="modal-body modal-body-select2">
+ <div class="modal-error"></div>
+ <div class="modal-warning"></div>
+ <div class="modal-notice"></div>
+
+ <div class="modal-field">
+ <h3><label for="coding-rules-bulk-change-profile">
+ {{#eq action 'change-severity'}}{{t 'coding_rules.change_severity_in'}}{{/eq}}
+ {{#eq action 'activate'}}{{t 'coding_rules.activate_in'}}{{/eq}}
+ {{#eq action 'deactivate'}}{{t 'coding_rules.deactivate_in'}}{{/eq}}
+ </label></h3>
+ {{#if qualityProfile}}
+ <h3 class="readonly-field">{{qualityProfileName}}{{#notEq action 'change-severity'}} —
+ {{t 'are_you_sure'}}{{/notEq}}</h3>
+ {{else}}
+ <select id="coding-rules-bulk-change-profile">
+ {{#each availableQualityProfiles}}
+ <option value="{{key}}">{{name}} - {{language}}</option>
+ {{/each}}
+ </select>
+ {{/if}}
+ </div>
+ </div>
+
+ <div class="modal-foot">
+ <button id="coding-rules-submit-bulk-change">{{t 'apply'}}</button>
+ <a id="coding-rules-cancel-bulk-change" class="action">{{t 'cancel'}}</a>
+ <a id="coding-rules-close-bulk-change" class="action" style="display:none" href="#">{{t 'close'}}</a>
+ </div>
+</form>
--- /dev/null
+<form>
+ <div class="modal-head">
+ {{#if change}}
+ <h2>{{t 'coding_rules.update_custom_rule'}}</h2>
+ {{else}}
+ <h2>{{t 'coding_rules.create_custom_rule'}}</h2>
+ {{/if}}
+ </div>
+
+ <div class="modal-body">
+ <div class="modal-error"></div>
+ <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
+
+ <table>
+ <tr class="property">
+ <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
+ <td>
+ <input type="text" name="name" id="coding-rules-custom-rule-creation-name"
+ class="coding-rules-name-key" value="{{name}}"/>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
+ <td>
+ {{#if change}}
+ <span class="coding-rules-detail-custom-rule-key" title="{{key}}">{{key}}</span>
+ {{else}}
+ <input type="text" name="key" id="coding-rules-custom-rule-creation-key"
+ class="coding-rules-name-key" value="{{internalKey}}"/>
+ {{/if}}
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
+ <td>
+ <textarea type="textarea" name="markdown_description" id="coding-rules-custom-rule-creation-html-description"
+ class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
+ <span class="right">{{> '_markdown-tips' }}</span>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'severity'}}</h3></th>
+ <td>
+ <select id="coding-rules-custom-rule-creation-severity">
+ {{#each severities}}
+ <option value="{{this}}">{{t 'severity' this}}</option>
+ {{/each}}
+ </select>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'coding_rules.filters.status'}}</h3></th>
+ <td>
+ <select id="coding-rules-custom-rule-creation-status">
+ {{#each statuses}}
+ <option value="{{id}}">{{text}}</option>
+ {{/each}}
+ </select>
+ </td>
+ </tr>
+ {{#each params}}
+ <tr class="property">
+ <th><h3>{{key}}</h3></th>
+ <td>
+ {{#eq type 'TEXT'}}
+ <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
+ {{else}}
+ <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}"/>
+ {{/eq}}
+ <div class="note">{{htmlDesc}}</div>
+ {{#if extra}}
+ <div class="note">{{extra}}</div>
+ {{/if}}
+ </td>
+ </tr>
+ {{/each}}
+ </table>
+ </div>
+
+ <div class="modal-foot">
+ <button id="coding-rules-custom-rule-creation-create">
+ {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+ </button>
+ <a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+ </div>
+</form>
--- /dev/null
+<button id="coding-rules-custom-rule-creation-reactivate">
+ {{t 'coding_rules.reactivate'}}
+</button>
+<button id="coding-rules-custom-rule-creation-create">
+ {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+</button>
+<a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
--- /dev/null
+<div class="coding-rules-debt-popup bubble-popup-container">
+ <ul class="bubble-popup-list">
+ {{#if debtRemFnType}}
+ <li>
+ <h3>{{t 'coding_rules.remediation_function'}}</h3>
+ {{t 'coding_rules.remediation_function' debtRemFnType}}
+ </li>
+ {{/if}}
+ {{#if debtRemFnCoeff}}
+ <li>
+ <h3>{{t 'coding_rules.remediation_function.coeff'}}</h3>
+ {{debtRemFnCoeff}}
+ </li>
+ {{/if}}
+ {{#if debtRemFnOffset}}
+ <li>
+ <h3>{{#eq debtRemFnType 'CONSTANT_ISSUE'}}
+ {{t 'coding_rules.remediation_function.constant'}}
+ {{else}}
+ {{t 'coding_rules.remediation_function.offset'}}
+ {{/eq}}
+ </h3>
+ {{debtRemFnOffset}}
+ </li>
+ {{/if}}
+</div>
+
+<div class="bubble-popup-arrow"></div>
--- /dev/null
+<td class="coding-rules-detail-custom-rule-name">
+ <a class="nolink" href="#rule_key={{key}}">{{name}}</a>
+</td>
+
+<td class="coding-rules-detail-custom-rule-severity">
+ {{severityIcon severity}} {{t "severity" severity}}
+</td>
+
+<td class="coding-rules-detail-custom-rule-parameters">
+ {{#each parameters}}
+ <div class="coding-rules-detail-custom-rule-parameter">
+ <span class="key">{{key}}</span><span class="sep">: </span><span class="value" title="{{value}}">{{value}}</span>
+ </div>
+ {{/each}}
+
+</td>
+
+{{#if canWrite}}
+<td class="coding-rules-detail-custom-rule-actions">
+ <div class="button-group">
+ <button class="coding-rules-detail-custom-rule-delete button-red">
+ {{t 'delete'}}
+ </button>
+ </div>
+</td>
+{{/if}}
--- /dev/null
+<table class="width100">
+ <tbody>
+ <tr>
+ <td class="coding-rules-detail-quality-profile-name">
+ {{name}}
+ {{#if parent}}
+ <div class="coding-rules-detail-quality-profile-inheritance">
+ {{#eq inherit 'OVERRIDES'}}
+ <i class="icon-inheritance" title="{{tp 'coding_rules.overrides' name parent.name}}"></i>
+ {{/eq}}
+ {{#eq inherit 'INHERITED'}}
+ <i class="icon-inheritance" title="{{tp 'coding_rules.inherits' name parent.name}}"></i>
+ {{/eq}}
+ {{parent.name}}
+ </div>
+ {{/if}}
+ </td>
+
+ {{#if severity}}
+ <td class="coding-rules-detail-quality-profile-severity">
+ {{severityIcon severity}} {{t "severity" severity}}
+ {{#if parent}}{{#notEq severity parent.severity}}
+ <div class="coding-rules-detail-quality-profile-inheritance">
+ {{t 'coding_rules.original'}} {{t 'severity' parent.severity}}
+ </div>
+ {{/notEq}}{{/if}}
+ </td>
+
+ {{#unless templateKey}}
+ <td class="coding-rules-detail-quality-profile-parameters">
+ {{#each parameters}}
+ <div class="coding-rules-detail-quality-profile-parameter">
+ <span class="key">{{key}}</span><span class="sep">: </span><span class="value" title="{{value}}">{{value}}</span>
+ {{#if ../parent}}{{#notEq value original}}
+ <div class="coding-rules-detail-quality-profile-inheritance">
+ {{t 'coding_rules.original'}} <span class="value">{{original}}</span>
+ </div>
+ {{/notEq}}{{/if}}
+ </div>
+ {{/each}}
+
+ </td>
+ {{/unless}}
+
+ {{#if canWrite}}
+ <td class="coding-rules-detail-quality-profile-actions">
+ <div class="button-group">
+ {{#unless isTemplate}}
+ <button class="coding-rules-detail-quality-profile-change">{{t 'change_verb'}}</button>
+ {{/unless}}
+ {{#if parent}}
+ {{#eq inherit 'OVERRIDES'}}
+ <button class="coding-rules-detail-quality-profile-revert button-red">
+ {{t 'coding_rules.revert_to_parent_definition'}}
+ </button>
+ {{/eq}}
+ {{else}}
+ <button class="coding-rules-detail-quality-profile-deactivate button-red">
+ {{t 'coding_rules.deactivate'}}
+ </button>
+ {{/if}}
+ </div>
+ </td>
+ {{/if}}
+
+ {{else}}
+ {{#if canWrite}}{{#unless isTemplate}}
+ <td class="coding-rules-detail-quality-profile-actions">
+ <div class="button-group">
+ <button class="coding-rules-detail-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+ </div>
+ </td>
+ {{/unless}}{{/if}}
+ {{/if}}
+ </tr>
+ </tbody>
+</table>
--- /dev/null
+<div class="coding-rules-detail-context"></div>
+
+<h3 class="coding-rules-detail-header">
+ {{name}}
+ <a class="coding-rules-detail-permalink" href="#rule_key={{key}}">
+ <i class="icon-link"></i> {{t 'coding_rules.permalink'}}
+ </a>
+</h3>
+<span class="subtitle">{{key}}</span>
+
+<ul class="coding-rules-detail-properties">
+ {{#unless isManual}}
+ <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
+ {{/unless}}
+ {{#notEq status 'READY'}}
+ <li class="coding-rules-detail-property">
+ <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
+ </li>
+ {{/notEq}}
+
+
+ <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
+ <i class="icon-tags"></i>
+ <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
+ </li>
+ {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
+ {{#if sysTags}}<i class="icon-tags"></i>
+ <span>{{join sysTags ', '}}</span>{{/if}}
+ <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
+
+ <div class="button-group">
+ <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
+ </div>
+ <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
+ </li>{{/if}}
+
+ {{#if subcharacteristic}}
+ <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subcharacteristic}}</li>
+ {{/if}}
+ <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
+ <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
+
+ {{#if isTemplate}}
+ <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
+ {{/if}}
+ {{#if templateKey}}
+ <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
+ (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
+ </li>
+ {{/if}}
+</ul>
+
+<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
+
+{{#unless isEditable}}
+ {{#unless isManual}}
+ <div class="coding-rules-detail-description coding-rules-detail-description-extra">
+ <div id="coding-rules-detail-description-extra">
+ {{#if htmlNote}}
+ <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
+ {{#if canWrite}}<div class="button-group">
+ <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
+ </div>{{/if}}
+ </div>
+
+ {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
+ <table class="width100">
+ <tbody>
+ <tr>
+ <td class="width100" colspan="2">
+ <textarea id="coding-rules-detail-extend-description-text" rows="4"
+ style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div class="button-group">
+ <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
+ {{#if mdNote}}
+ <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
+ {{/if}}
+ </div>
+ <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
+ </td>
+ <td class="right">
+ {{> '_markdown-tips' }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div id="coding-rules-detail-extend-description-spinner">
+ <i class="spinner"></i>
+ </div>{{/if}}
+ </div>
+ {{/unless}}
+{{/unless}}
+
+
+{{#if params}}
+ <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
+ <div class="coding-rules-detail-parameters">
+ {{#each params}}
+ <dl class="coding-rules-detail-parameter">
+ <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
+ <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
+ <p>{{{htmlDesc}}}</p>
+ {{#if ../../templateKey}}
+ <div class="subtitle">
+ {{#if defaultValue }}
+ <span class="value">{{defaultValue}}</span>
+ {{else}}
+ {{t 'coding_rules.parameter.empty'}}
+ {{/if}}
+ </div>
+ {{else}}
+ {{#if defaultValue}}
+ <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
+ {{/if}}
+ {{/if}}
+ </dd>
+ </dl>
+ {{/each}}
+ </div>
+{{/if}}
+
+{{#if isEditable}}
+ <div class="coding-rules-detail-description">
+ <div class="button-group">
+ {{#if isManual}}
+ <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button>
+ {{else}}
+ <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button>
+ {{/if}}
+ <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button>
+ </div>
+ </div>
+{{/if}}
+
+
+{{#if isTemplate}}
+<div class="coding-rules-detail-custom-rules-section">
+ <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
+
+ {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+ <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
+ </div>{{/if}}
+ <div id="coding-rules-detail-custom-rules"></div>
+</div>
+{{/if}}
+
+
+{{#if qualityProfilesVisible}}
+<div class="coding-rules-detail-quality-profiles-section">
+ <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
+
+ {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+ <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+ </div>{{/unless}}{{/if}}
+ {{#if isTemplate}}
+ <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
+ {{/if}}
+ <div id="coding-rules-detail-quality-profiles"></div>
+</div>
+{{/if}}
--- /dev/null
+<div class="navigator-facets-list">
+ {{#unless items}}
+ {{t 'coding_rules.no_results'}}
+ {{/unless}}
+ {{#each items}}
+ <div class="navigator-facets-list-item" data-property="{{property}}">
+ <div class="navigator-facets-list-item-name">
+ {{#if limitReached}}
+ {{tp 'coding_rules.facets.top' property_message}}
+ {{else}}
+ {{property_message}}
+ {{/if}}
+ </div>
+ <div class="navigator-facets-list-item-options">
+ {{#each values}}
+ {{#if count}}
+ <a class="facet" data-key="{{val}}" data-property="{{../property}}">
+ <span class="facet-name">{{text}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/if}}
+ {{/each}}
+ </div>
+ </div>
+ {{/each}}
+</div>
--- /dev/null
+<div class="navigator-filters-list"></div>
+<button class="navigator-filter-submit">{{t 'search_verb'}}</button>
\ No newline at end of file
--- /dev/null
+<h1 class="navigator-header-title">{{t 'coding_rules.page'}}</h1>
+
+<div class="navigator-header-actions button-group">
+ <button id="coding-rules-new-search">{{t 'coding_rules.new_search'}}</button>
+ {{#if canWrite}}<button id="coding-rules-create-rule">{{t 'coding_rules.create'}}</button>{{/if}}
+</div>
--- /dev/null
+<div class="navigator-header"></div>
+<div class="navigator-filters"></div>
+<div class="navigator-facets"></div>
+
+<div class="navigator-content">
+ <div class="navigator-side">
+ <div style="position:relative; overflow: visible; height: 100%;">
+ <div class="navigator-actions"></div>
+ <div class="navigator-results"></div>
+ <a class="navigator-resizer"><i class="icon-resizer"></i></a>
+ </div>
+ </div>
+ <div class="navigator-main">
+ <div class="navigator-details"></div>
+ </div>
+</div>
\ No newline at end of file
--- /dev/null
+{{t 'coding_rules.no_results'}}
\ No newline at end of file
--- /dev/null
+<div class="line line-small">
+ <span class="coding-rules-detail-status">{{default language manualRuleLabel}}</span>
+
+ {{#if allTags}}
+
+ <span class="coding-rules-list-tags">
+ <i class="icon-tags"></i>
+ <span>{{join allTags ', '}}</span>
+ </span>
+ {{/if}}
+
+ {{#notEq status 'READY'}}
+ <div class="line-right">
+ <span class="coding-rules-detail-not-ready">{{status}}</span>
+ </div>
+ {{/notEq}}
+</div>
+
+<div class="line" title="{{name}}" name="{{key}}">{{name}}</div>
--- /dev/null
+<form>
+ <div class="modal-head">
+ {{#if change}}
+ <h2>{{t 'coding_rules.update_manual_rule'}}</h2>
+ {{else}}
+ <h2>{{t 'coding_rules.create_manual_rule'}}</h2>
+ {{/if}}
+ </div>
+
+ <div class="modal-body">
+ <div class="modal-error"></div>
+ <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
+
+ <table>
+ <tr class="property">
+ <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
+ <td>
+ <input type="text" name="name" id="coding-rules-manual-rule-creation-name"
+ class="coding-rules-name-key" value="{{name}}"/>
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
+ <td>
+ {{#if change}}
+ {{key}}
+ {{else}}
+ <input type="text" name="key" id="coding-rules-manual-rule-creation-key"
+ class="coding-rules-name-key" value="{{internalKey}}"/>
+ {{/if}}
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
+ <td>
+ <textarea type="textarea" name="markdown_description" id="coding-rules-manual-rule-creation-html-description"
+ class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
+ <span class="right">{{> '_markdown-tips' }}</span>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <div class="modal-foot">
+ <button id="coding-rules-manual-rule-creation-create">
+ {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+ </button>
+ <a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+ </div>
+</form>
--- /dev/null
+<button id="coding-rules-manual-rule-creation-reactivate">
+ {{t 'coding_rules.reactivate'}}
+</button>
+<button id="coding-rules-manual-rule-creation-create">
+ {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
+</button>
+<a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
--- /dev/null
+<div class="coding-rules-parameter-full-description bubble-popup-container">
+ <div class="bubble-popup-title">{{key}}</div>
+
+ {{{htmlDesc}}}
+ {{#if defaultValue}}
+ <div>
+ {{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
+ </div>
+ {{/if}}
+</div>
+
+<div class="bubble-popup-arrow"></div>
--- /dev/null
+<li>
+ <label title="{{id}}" data-id="{{id}}">
+ <span>
+ <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
+ {{text}}
+ </span>
+
+ {{#if language}}
+ <br>
+ <span>
+ <i class="icon-checkbox icon-checkbox-invisible"></i>
+ <span class="subtitle">{{language}}</span>
+ </span>
+ {{/if}}
+ </label>
+</li>
--- /dev/null
+<form>
+ <div class="modal-head">
+ {{#if change}}
+ <h2>{{t 'coding_rules.change_details'}}</h2>
+ {{else}}
+ <h2>{{t 'coding_rules.activate_in_quality_profile'}}</h2>
+ {{/if}}
+ </div>
+
+ <div class="modal-body modal-body-select2">
+ <div class="modal-error"></div>
+
+ <table>
+ <tr class="property">
+ <th><h3>{{t 'coding_rules.quality_profile'}}</h3></th>
+ <td>
+ {{#if key}}
+ {{name}}
+ {{else}}
+ <select id="coding-rules-quality-profile-activation-select">
+ {{#each qualityProfiles}}
+ <option value="{{key}}">{{name}}</option>
+ {{/each}}
+ </select>
+ {{/if}}
+ </td>
+ </tr>
+ <tr class="property">
+ <th><h3>{{t 'severity'}}</h3></th>
+ <td>
+ <select id="coding-rules-quality-profile-activation-severity">
+ {{#each severities}}
+ <option value="{{this}}">{{t 'severity' this}}</option>
+ {{/each}}
+ </select>
+ </td>
+ </tr>
+ {{#if isCustomRule}}
+ <tr class="property">
+ <td colspan="2" class="note">{{t 'coding_rules.custom_rule.activation_notice'}}</td>
+ {{else}}
+ {{#each params}}
+ <tr class="property">
+ <th><h3>{{key}}</h3></th>
+ <td>
+ {{#eq type 'TEXT'}}
+ <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
+ {{else}}
+ {{#eq type 'BOOLEAN'}}
+ <select name="{{key}}" value="{{value}}">
+ <option value="{{defaultValue}}">{{t 'default'}} ({{t defaultValue}})</option>
+ <option value="true"{{#eq value 'true'}} selected="selected"{{/eq}}>{{t 'true'}}</option>
+ <option value="false"{{#eq value 'false'}} selected="selected"{{/eq}}>{{t 'false'}}</option>
+ </select>
+ {{else}}
+ <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}">
+ {{/eq}}
+ {{/eq}}
+ <div class="note">{{description}}</div>
+ {{#if extra}}
+ <div class="note">{{extra}}</div>
+ {{/if}}
+ </td>
+ </tr>
+ {{/each}}
+ {{/if}}
+ </table>
+ </div>
+
+ <div class="modal-foot">
+ <button id="coding-rules-quality-profile-activation-activate" {{#unless saveEnabled}}disabled="disabled"{{/unless}}>
+ {{#if change}}{{t 'save'}}{{else}}{{t 'coding_rules.activate'}}{{/if}}
+ </button>
+ <a id="coding-rules-quality-profile-activation-cancel" class="action">{{t 'cancel'}}</a>
+ </div>
+</form>
--- /dev/null
+<input type="text"
+ size="{{size}}" name="{{property}}" value="{{value}}"
+ class="query-filter-input"/>
--- /dev/null
+<li>
+ <label title="{{id}}" data-id="{{id}}">
+ <span>
+ <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
+ {{text}}
+ </span>
+
+ {{#if language}}
+ <br>
+ <span>
+ <i class="icon-checkbox icon-checkbox-invisible"></i>
+ <span class="subtitle">{{language}}</span>
+ </span>
+ {{/if}}
+ </label>
+</li>
+++ /dev/null
-<div class="navigator-actions-order">
- {{#if sorting}}
- {{t 'coding_rules.ordered_by'}} <strong>{{sorting.sortText}}</strong> {{#if sorting.asc}}<i class="icon-sort-asc"></i>{{else}}<i class="icon-sort-desc"></i>{{/if}}
- {{else}}
- {{t 'coding_rules.order'}}
- {{/if}}
-</div>
-<ul class="navigator-actions-order-choices">
- <li data-sort="" data-asc="">{{t 'coding_rules.sort.relevance'}}</li>
- <li data-sort="createdAt" data-asc="true">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-asc"></i></li>
- <li data-sort="createdAt" data-asc="false">{{t 'coding_rules.sort.creation_date'}} <i class="icon-sort-desc"></i></li>
- <li data-sort="name" data-asc="true">{{t 'coding_rules.sort.name'}} <i class="icon-sort-asc"></i></li>
- <li data-sort="name" data-asc="false">{{t 'coding_rules.sort.name'}} <i class="icon-sort-desc"></i></li>
-</ul>
-<div class="navigator-actions-total">
- {{t 'coding_rules.found'}}: <strong>{{paging.total}}</strong>
- {{#if canWrite}}<a class="navigator-actions-bulk icon-bulk-change" title="{{t 'bulk_change'}}"></a>{{/if}}
-</div>
+++ /dev/null
-{{! activation }}
-
-<a class="coding-rules-bulk-change-dropdown-link" data-action="activate">
- {{t 'coding_rules.activate_in'}}…
-</a>
-
-{{#if allowActivateOnProfile}}
- <a class="coding-rules-bulk-change-dropdown-link" data-action="activate" data-param="{{qualityProfile}}">
- {{t 'coding_rules.activate_in'}} <strong>{{qualityProfileName}}</strong>
- </a>
-{{/if}}
-
-
-
-{{! deactivation }}
-
-<a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate">
- {{t 'coding_rules.deactivate_in'}}…
-</a>
-
-{{#if allowDeactivateOnProfile}}
- <a class="coding-rules-bulk-change-dropdown-link" data-action="deactivate" data-param="{{qualityProfile}}">
- {{tp 'coding_rules.deactivate_in'}} <strong>{{qualityProfileName}}</strong>
- </a>
-{{/if}}
+++ /dev/null
-<form>
- <div class="modal-head">
- {{#eq action 'activate'}}
- <h2>{{t 'coding_rules.activate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
- {{/eq}}
- {{#eq action 'deactivate'}}
- <h2>{{t 'coding_rules.deactivate_in_quality_profile'}} ({{paging.total}} {{t 'coding_rules._rules'}})</h2>
- {{/eq}}
- </div>
-
- <div class="modal-body modal-body-select2">
- <div class="modal-error"></div>
- <div class="modal-warning"></div>
- <div class="modal-notice"></div>
-
- <div class="modal-field">
- <h3><label for="coding-rules-bulk-change-profile">
- {{#eq action 'change-severity'}}{{t 'coding_rules.change_severity_in'}}{{/eq}}
- {{#eq action 'activate'}}{{t 'coding_rules.activate_in'}}{{/eq}}
- {{#eq action 'deactivate'}}{{t 'coding_rules.deactivate_in'}}{{/eq}}
- </label></h3>
- {{#if qualityProfile}}
- <h3 class="readonly-field">{{qualityProfileName}}{{#notEq action 'change-severity'}} —
- {{t 'are_you_sure'}}{{/notEq}}</h3>
- {{else}}
- <select id="coding-rules-bulk-change-profile">
- {{#each availableQualityProfiles}}
- <option value="{{key}}">{{name}} - {{language}}</option>
- {{/each}}
- </select>
- {{/if}}
- </div>
- </div>
-
- <div class="modal-foot">
- <button id="coding-rules-submit-bulk-change">{{t 'apply'}}</button>
- <a id="coding-rules-cancel-bulk-change" class="action">{{t 'cancel'}}</a>
- <a id="coding-rules-close-bulk-change" class="action" style="display:none" href="#">{{t 'close'}}</a>
- </div>
-</form>
+++ /dev/null
-<form>
- <div class="modal-head">
- {{#if change}}
- <h2>{{t 'coding_rules.update_custom_rule'}}</h2>
- {{else}}
- <h2>{{t 'coding_rules.create_custom_rule'}}</h2>
- {{/if}}
- </div>
-
- <div class="modal-body">
- <div class="modal-error"></div>
- <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
-
- <table>
- <tr class="property">
- <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
- <td>
- <input type="text" name="name" id="coding-rules-custom-rule-creation-name"
- class="coding-rules-name-key" value="{{name}}"/>
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
- <td>
- {{#if change}}
- <span class="coding-rules-detail-custom-rule-key" title="{{key}}">{{key}}</span>
- {{else}}
- <input type="text" name="key" id="coding-rules-custom-rule-creation-key"
- class="coding-rules-name-key" value="{{internalKey}}"/>
- {{/if}}
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
- <td>
- <textarea type="textarea" name="markdown_description" id="coding-rules-custom-rule-creation-html-description"
- class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
- <span class="right">{{> '_markdown-tips' }}</span>
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'severity'}}</h3></th>
- <td>
- <select id="coding-rules-custom-rule-creation-severity">
- {{#each severities}}
- <option value="{{this}}">{{t 'severity' this}}</option>
- {{/each}}
- </select>
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'coding_rules.filters.status'}}</h3></th>
- <td>
- <select id="coding-rules-custom-rule-creation-status">
- {{#each statuses}}
- <option value="{{id}}">{{text}}</option>
- {{/each}}
- </select>
- </td>
- </tr>
- {{#each params}}
- <tr class="property">
- <th><h3>{{key}}</h3></th>
- <td>
- {{#eq type 'TEXT'}}
- <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
- {{else}}
- <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}"/>
- {{/eq}}
- <div class="note">{{htmlDesc}}</div>
- {{#if extra}}
- <div class="note">{{extra}}</div>
- {{/if}}
- </td>
- </tr>
- {{/each}}
- </table>
- </div>
-
- <div class="modal-foot">
- <button id="coding-rules-custom-rule-creation-create">
- {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
- </button>
- <a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
- </div>
-</form>
+++ /dev/null
-<button id="coding-rules-custom-rule-creation-reactivate">
- {{t 'coding_rules.reactivate'}}
-</button>
-<button id="coding-rules-custom-rule-creation-create">
- {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
-</button>
-<a id="coding-rules-custom-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+++ /dev/null
-<div class="coding-rules-debt-popup bubble-popup-container">
- <ul class="bubble-popup-list">
- {{#if debtRemFnType}}
- <li>
- <h3>{{t 'coding_rules.remediation_function'}}</h3>
- {{t 'coding_rules.remediation_function' debtRemFnType}}
- </li>
- {{/if}}
- {{#if debtRemFnCoeff}}
- <li>
- <h3>{{t 'coding_rules.remediation_function.coeff'}}</h3>
- {{debtRemFnCoeff}}
- </li>
- {{/if}}
- {{#if debtRemFnOffset}}
- <li>
- <h3>{{#eq debtRemFnType 'CONSTANT_ISSUE'}}
- {{t 'coding_rules.remediation_function.constant'}}
- {{else}}
- {{t 'coding_rules.remediation_function.offset'}}
- {{/eq}}
- </h3>
- {{debtRemFnOffset}}
- </li>
- {{/if}}
-</div>
-
-<div class="bubble-popup-arrow"></div>
+++ /dev/null
-<td class="coding-rules-detail-custom-rule-name">
- <a class="nolink" href="#rule_key={{key}}">{{name}}</a>
-</td>
-
-<td class="coding-rules-detail-custom-rule-severity">
- {{severityIcon severity}} {{t "severity" severity}}
-</td>
-
-<td class="coding-rules-detail-custom-rule-parameters">
- {{#each parameters}}
- <div class="coding-rules-detail-custom-rule-parameter">
- <span class="key">{{key}}</span><span class="sep">: </span><span class="value" title="{{value}}">{{value}}</span>
- </div>
- {{/each}}
-
-</td>
-
-{{#if canWrite}}
-<td class="coding-rules-detail-custom-rule-actions">
- <div class="button-group">
- <button class="coding-rules-detail-custom-rule-delete button-red">
- {{t 'delete'}}
- </button>
- </div>
-</td>
-{{/if}}
+++ /dev/null
-<table class="width100">
- <tbody>
- <tr>
- <td class="coding-rules-detail-quality-profile-name">
- {{name}}
- {{#if parent}}
- <div class="coding-rules-detail-quality-profile-inheritance">
- {{#eq inherit 'OVERRIDES'}}
- <i class="icon-inheritance" title="{{tp 'coding_rules.overrides' name parent.name}}"></i>
- {{/eq}}
- {{#eq inherit 'INHERITED'}}
- <i class="icon-inheritance" title="{{tp 'coding_rules.inherits' name parent.name}}"></i>
- {{/eq}}
- {{parent.name}}
- </div>
- {{/if}}
- </td>
-
- {{#if severity}}
- <td class="coding-rules-detail-quality-profile-severity">
- {{severityIcon severity}} {{t "severity" severity}}
- {{#if parent}}{{#notEq severity parent.severity}}
- <div class="coding-rules-detail-quality-profile-inheritance">
- {{t 'coding_rules.original'}} {{t 'severity' parent.severity}}
- </div>
- {{/notEq}}{{/if}}
- </td>
-
- {{#unless templateKey}}
- <td class="coding-rules-detail-quality-profile-parameters">
- {{#each parameters}}
- <div class="coding-rules-detail-quality-profile-parameter">
- <span class="key">{{key}}</span><span class="sep">: </span><span class="value" title="{{value}}">{{value}}</span>
- {{#if ../parent}}{{#notEq value original}}
- <div class="coding-rules-detail-quality-profile-inheritance">
- {{t 'coding_rules.original'}} <span class="value">{{original}}</span>
- </div>
- {{/notEq}}{{/if}}
- </div>
- {{/each}}
-
- </td>
- {{/unless}}
-
- {{#if canWrite}}
- <td class="coding-rules-detail-quality-profile-actions">
- <div class="button-group">
- {{#unless isTemplate}}
- <button class="coding-rules-detail-quality-profile-change">{{t 'change_verb'}}</button>
- {{/unless}}
- {{#if parent}}
- {{#eq inherit 'OVERRIDES'}}
- <button class="coding-rules-detail-quality-profile-revert button-red">
- {{t 'coding_rules.revert_to_parent_definition'}}
- </button>
- {{/eq}}
- {{else}}
- <button class="coding-rules-detail-quality-profile-deactivate button-red">
- {{t 'coding_rules.deactivate'}}
- </button>
- {{/if}}
- </div>
- </td>
- {{/if}}
-
- {{else}}
- {{#if canWrite}}{{#unless isTemplate}}
- <td class="coding-rules-detail-quality-profile-actions">
- <div class="button-group">
- <button class="coding-rules-detail-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
- </div>
- </td>
- {{/unless}}{{/if}}
- {{/if}}
- </tr>
- </tbody>
-</table>
+++ /dev/null
-<div class="coding-rules-detail-context"></div>
-
-<h3 class="coding-rules-detail-header">
- {{name}}
- <a class="coding-rules-detail-permalink" href="#rule_key={{key}}">
- <i class="icon-link"></i> {{t 'coding_rules.permalink'}}
- </a>
-</h3>
-<span class="subtitle">{{key}}</span>
-
-<ul class="coding-rules-detail-properties">
- {{#unless isManual}}
- <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
- {{/unless}}
- {{#notEq status 'READY'}}
- <li class="coding-rules-detail-property">
- <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
- </li>
- {{/notEq}}
-
-
- <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
- <i class="icon-tags"></i>
- <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
- </li>
- {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
- {{#if sysTags}}<i class="icon-tags"></i>
- <span>{{join sysTags ', '}}</span>{{/if}}
- <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
-
- <div class="button-group">
- <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
- </div>
- <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
- </li>{{/if}}
-
- {{#if subcharacteristic}}
- <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subcharacteristic}}</li>
- {{/if}}
- <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
- <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
-
- {{#if isTemplate}}
- <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
- {{/if}}
- {{#if templateKey}}
- <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
- (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
- </li>
- {{/if}}
-</ul>
-
-<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
-
-{{#unless isEditable}}
- {{#unless isManual}}
- <div class="coding-rules-detail-description coding-rules-detail-description-extra">
- <div id="coding-rules-detail-description-extra">
- {{#if htmlNote}}
- <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
- {{#if canWrite}}<div class="button-group">
- <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
- </div>{{/if}}
- </div>
-
- {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
- <table class="width100">
- <tbody>
- <tr>
- <td class="width100" colspan="2">
- <textarea id="coding-rules-detail-extend-description-text" rows="4"
- style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
- </td>
- </tr>
- <tr>
- <td>
- <div class="button-group">
- <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
- {{#if mdNote}}
- <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
- {{/if}}
- </div>
- <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
- </td>
- <td class="right">
- {{> '_markdown-tips' }}
- </td>
- </tr>
- </tbody>
- </table>
- </div>
-
- <div id="coding-rules-detail-extend-description-spinner">
- <i class="spinner"></i>
- </div>{{/if}}
- </div>
- {{/unless}}
-{{/unless}}
-
-
-{{#if params}}
- <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
- <div class="coding-rules-detail-parameters">
- {{#each params}}
- <dl class="coding-rules-detail-parameter">
- <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
- <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
- <p>{{{htmlDesc}}}</p>
- {{#if ../../templateKey}}
- <div class="subtitle">
- {{#if defaultValue }}
- <span class="value">{{defaultValue}}</span>
- {{else}}
- {{t 'coding_rules.parameter.empty'}}
- {{/if}}
- </div>
- {{else}}
- {{#if defaultValue}}
- <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
- {{/if}}
- {{/if}}
- </dd>
- </dl>
- {{/each}}
- </div>
-{{/if}}
-
-{{#if isEditable}}
- <div class="coding-rules-detail-description">
- <div class="button-group">
- {{#if isManual}}
- <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button>
- {{else}}
- <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button>
- {{/if}}
- <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button>
- </div>
- </div>
-{{/if}}
-
-
-{{#if isTemplate}}
-<div class="coding-rules-detail-custom-rules-section">
- <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
-
- {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
- <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
- </div>{{/if}}
- <div id="coding-rules-detail-custom-rules"></div>
-</div>
-{{/if}}
-
-
-{{#if qualityProfilesVisible}}
-<div class="coding-rules-detail-quality-profiles-section">
- <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
-
- {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
- <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
- </div>{{/unless}}{{/if}}
- {{#if isTemplate}}
- <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
- {{/if}}
- <div id="coding-rules-detail-quality-profiles"></div>
-</div>
-{{/if}}
+++ /dev/null
-<div class="navigator-facets-list">
- {{#unless items}}
- {{t 'coding_rules.no_results'}}
- {{/unless}}
- {{#each items}}
- <div class="navigator-facets-list-item" data-property="{{property}}">
- <div class="navigator-facets-list-item-name">
- {{#if limitReached}}
- {{tp 'coding_rules.facets.top' property_message}}
- {{else}}
- {{property_message}}
- {{/if}}
- </div>
- <div class="navigator-facets-list-item-options">
- {{#each values}}
- {{#if count}}
- <a class="facet" data-key="{{val}}" data-property="{{../property}}">
- <span class="facet-name">{{text}}</span>
- <span class="facet-stat">{{count}}</span>
- </a>
- {{/if}}
- {{/each}}
- </div>
- </div>
- {{/each}}
-</div>
+++ /dev/null
-<div class="navigator-filters-list"></div>
-<button class="navigator-filter-submit">{{t 'search_verb'}}</button>
\ No newline at end of file
--- /dev/null
+<div class="search-navigator-filters-header">
+ <span class="search-navigator-filters-name">{{t 'coding_rules.page'}}</span>
+</div>
+
+<div class="search-navigator-filters-actions">
+ <div class="button-group">
+ <button class="js-new-search" id="coding-rules-new-search">{{t 'issue_filter.new_search'}}</button>
+ </div>
+</div>
+++ /dev/null
-<h1 class="navigator-header-title">{{t 'coding_rules.page'}}</h1>
-
-<div class="navigator-header-actions button-group">
- <button id="coding-rules-new-search">{{t 'coding_rules.new_search'}}</button>
- {{#if canWrite}}<button id="coding-rules-create-rule">{{t 'coding_rules.create'}}</button>{{/if}}
-</div>
-<div class="navigator-header"></div>
-<div class="navigator-filters"></div>
-<div class="navigator-facets"></div>
+<div class="search-navigator-side">
+ <div class="search-navigator-filters"></div>
+ <div class="search-navigator-facets"></div>
+</div>
-<div class="navigator-content">
- <div class="navigator-side">
- <div style="position:relative; overflow: visible; height: 100%;">
- <div class="navigator-actions"></div>
- <div class="navigator-results"></div>
- <a class="navigator-resizer"><i class="icon-resizer"></i></a>
- </div>
- </div>
- <div class="navigator-main">
- <div class="navigator-details"></div>
- </div>
-</div>
\ No newline at end of file
+<div class="search-navigator-workspace">
+ <div class="search-navigator-workspace-header"></div>
+ <div class="search-navigator-workspace-list"></div>
+ <div class="search-navigator-workspace-details"></div>
+</div>
+++ /dev/null
-{{t 'coding_rules.no_results'}}
\ No newline at end of file
+++ /dev/null
-<div class="line line-small">
- <span class="coding-rules-detail-status">{{default language manualRuleLabel}}</span>
-
- {{#if allTags}}
-
- <span class="coding-rules-list-tags">
- <i class="icon-tags"></i>
- <span>{{join allTags ', '}}</span>
- </span>
- {{/if}}
-
- {{#notEq status 'READY'}}
- <div class="line-right">
- <span class="coding-rules-detail-not-ready">{{status}}</span>
- </div>
- {{/notEq}}
-</div>
-
-<div class="line" title="{{name}}" name="{{key}}">{{name}}</div>
+++ /dev/null
-<form>
- <div class="modal-head">
- {{#if change}}
- <h2>{{t 'coding_rules.update_manual_rule'}}</h2>
- {{else}}
- <h2>{{t 'coding_rules.create_manual_rule'}}</h2>
- {{/if}}
- </div>
-
- <div class="modal-body">
- <div class="modal-error"></div>
- <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div>
-
- <table>
- <tr class="property">
- <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th>
- <td>
- <input type="text" name="name" id="coding-rules-manual-rule-creation-name"
- class="coding-rules-name-key" value="{{name}}"/>
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th>
- <td>
- {{#if change}}
- {{key}}
- {{else}}
- <input type="text" name="key" id="coding-rules-manual-rule-creation-key"
- class="coding-rules-name-key" value="{{internalKey}}"/>
- {{/if}}
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th>
- <td>
- <textarea type="textarea" name="markdown_description" id="coding-rules-manual-rule-creation-html-description"
- class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea>
- <span class="right">{{> '_markdown-tips' }}</span>
- </td>
- </tr>
- </table>
- </div>
-
- <div class="modal-foot">
- <button id="coding-rules-manual-rule-creation-create">
- {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
- </button>
- <a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
- </div>
-</form>
+++ /dev/null
-<button id="coding-rules-manual-rule-creation-reactivate">
- {{t 'coding_rules.reactivate'}}
-</button>
-<button id="coding-rules-manual-rule-creation-create">
- {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}}
-</button>
-<a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a>
+++ /dev/null
-<div class="coding-rules-parameter-full-description bubble-popup-container">
- <div class="bubble-popup-title">{{key}}</div>
-
- {{{htmlDesc}}}
- {{#if defaultValue}}
- <div>
- {{t 'coding_rules.parameters.default_value'}} {{defaultValue}}
- </div>
- {{/if}}
-</div>
-
-<div class="bubble-popup-arrow"></div>
+++ /dev/null
-<li>
- <label title="{{id}}" data-id="{{id}}">
- <span>
- <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
- {{text}}
- </span>
-
- {{#if language}}
- <br>
- <span>
- <i class="icon-checkbox icon-checkbox-invisible"></i>
- <span class="subtitle">{{language}}</span>
- </span>
- {{/if}}
- </label>
-</li>
+++ /dev/null
-<form>
- <div class="modal-head">
- {{#if change}}
- <h2>{{t 'coding_rules.change_details'}}</h2>
- {{else}}
- <h2>{{t 'coding_rules.activate_in_quality_profile'}}</h2>
- {{/if}}
- </div>
-
- <div class="modal-body modal-body-select2">
- <div class="modal-error"></div>
-
- <table>
- <tr class="property">
- <th><h3>{{t 'coding_rules.quality_profile'}}</h3></th>
- <td>
- {{#if key}}
- {{name}}
- {{else}}
- <select id="coding-rules-quality-profile-activation-select">
- {{#each qualityProfiles}}
- <option value="{{key}}">{{name}}</option>
- {{/each}}
- </select>
- {{/if}}
- </td>
- </tr>
- <tr class="property">
- <th><h3>{{t 'severity'}}</h3></th>
- <td>
- <select id="coding-rules-quality-profile-activation-severity">
- {{#each severities}}
- <option value="{{this}}">{{t 'severity' this}}</option>
- {{/each}}
- </select>
- </td>
- </tr>
- {{#if isCustomRule}}
- <tr class="property">
- <td colspan="2" class="note">{{t 'coding_rules.custom_rule.activation_notice'}}</td>
- {{else}}
- {{#each params}}
- <tr class="property">
- <th><h3>{{key}}</h3></th>
- <td>
- {{#eq type 'TEXT'}}
- <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
- {{else}}
- {{#eq type 'BOOLEAN'}}
- <select name="{{key}}" value="{{value}}">
- <option value="{{defaultValue}}">{{t 'default'}} ({{t defaultValue}})</option>
- <option value="true"{{#eq value 'true'}} selected="selected"{{/eq}}>{{t 'true'}}</option>
- <option value="false"{{#eq value 'false'}} selected="selected"{{/eq}}>{{t 'false'}}</option>
- </select>
- {{else}}
- <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}">
- {{/eq}}
- {{/eq}}
- <div class="note">{{description}}</div>
- {{#if extra}}
- <div class="note">{{extra}}</div>
- {{/if}}
- </td>
- </tr>
- {{/each}}
- {{/if}}
- </table>
- </div>
-
- <div class="modal-foot">
- <button id="coding-rules-quality-profile-activation-activate" {{#unless saveEnabled}}disabled="disabled"{{/unless}}>
- {{#if change}}{{t 'save'}}{{else}}{{t 'coding_rules.activate'}}{{/if}}
- </button>
- <a id="coding-rules-quality-profile-activation-cancel" class="action">{{t 'cancel'}}</a>
- </div>
-</form>
+++ /dev/null
-<input type="text"
- size="{{size}}" name="{{property}}" value="{{value}}"
- class="query-filter-input"/>
+++ /dev/null
-<li>
- <label title="{{id}}" data-id="{{id}}">
- <span>
- <i class="icon-checkbox {{#if checked}}icon-checkbox-checked{{/if}} {{#unless multiple}}icon-checkbox-single{{/unless}}"></i>
- {{text}}
- </span>
-
- {{#if language}}
- <br>
- <span>
- <i class="icon-checkbox icon-checkbox-invisible"></i>
- <span class="subtitle">{{language}}</span>
- </span>
- {{/if}}
- </label>
-</li>
--- /dev/null
+<h3 class="coding-rules-detail-header">
+ {{name}}
+ <a class="coding-rules-detail-permalink icon-link" target="_blank" href="#rule_key={{key}}"></a>
+</h3>
+<span class="subtitle">{{key}}</span>
+
+<ul class="coding-rules-detail-properties">
+ {{#unless isManual}}
+ <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
+ {{/unless}}
+ {{#notEq status 'READY'}}
+ <li class="coding-rules-detail-property">
+ <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
+ </li>
+ {{/notEq}}
+
+
+ <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
+ <i class="icon-tags"></i>
+ <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
+ </li>
+ {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
+ {{#if sysTags}}<i class="icon-tags"></i>
+ <span>{{join sysTags ', '}}</span>{{/if}}
+ <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
+
+ <div class="button-group">
+ <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
+ </div>
+ <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
+ </li>{{/if}}
+
+ {{#if subCharacteristic}}
+ <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subCharacteristic}}</li>
+ {{/if}}
+ <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
+ <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
+
+ {{#if isTemplate}}
+ <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
+ {{/if}}
+ {{#if templateKey}}
+ <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
+ (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
+ </li>
+ {{/if}}
+</ul>
+
+<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
+
+{{#unless isEditable}}
+ {{#unless isManual}}
+ <div class="coding-rules-detail-description coding-rules-detail-description-extra">
+ <div id="coding-rules-detail-description-extra">
+ {{#if htmlNote}}
+ <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
+ {{#if canWrite}}<div class="button-group">
+ <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
+ </div>{{/if}}
+ </div>
+
+ {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
+ <table class="width100">
+ <tbody>
+ <tr>
+ <td class="width100" colspan="2">
+ <textarea id="coding-rules-detail-extend-description-text" rows="4"
+ style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div class="button-group">
+ <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
+ {{#if mdNote}}
+ <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
+ {{/if}}
+ </div>
+ <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
+ </td>
+ <td class="right">
+ {{> '_markdown-tips' }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div id="coding-rules-detail-extend-description-spinner">
+ <i class="spinner"></i>
+ </div>{{/if}}
+ </div>
+ {{/unless}}
+{{/unless}}
+
+
+{{#if params}}
+ <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
+ <div class="coding-rules-detail-parameters">
+ {{#each params}}
+ <dl class="coding-rules-detail-parameter">
+ <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
+ <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
+ <p>{{{htmlDesc}}}</p>
+ {{#if ../../templateKey}}
+ <div class="subtitle">
+ {{#if defaultValue }}
+ <span class="value">{{defaultValue}}</span>
+ {{else}}
+ {{t 'coding_rules.parameter.empty'}}
+ {{/if}}
+ </div>
+ {{else}}
+ {{#if defaultValue}}
+ <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
+ {{/if}}
+ {{/if}}
+ </dd>
+ </dl>
+ {{/each}}
+ </div>
+{{/if}}
+
+{{#if isEditable}}
+ <div class="coding-rules-detail-description">
+ <div class="button-group">
+ {{#if isManual}}
+ <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button>
+ {{else}}
+ <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button>
+ {{/if}}
+ <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button>
+ </div>
+ </div>
+{{/if}}
+
+
+{{#if isTemplate}}
+ <div class="coding-rules-detail-custom-rules-section">
+ <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
+
+ {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+ <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
+ </div>{{/if}}
+ <div id="coding-rules-detail-custom-rules"></div>
+ </div>
+{{/if}}
+
+
+{{#if qualityProfilesVisible}}
+ <div class="coding-rules-detail-quality-profiles-section">
+ <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
+
+ {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
+ <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+ </div>{{/unless}}{{/if}}
+ {{#if isTemplate}}
+ <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
+ {{/if}}
+ <div id="coding-rules-detail-quality-profiles"></div>
+ </div>
+{{/if}}
--- /dev/null
+<div class="search-navigator-header-component">
+ {{#if state.rule}}
+ <a class="js-back">{{t 'coding_rules.return_to_list'}}</a>
+ {{else}}
+
+ {{/if}}
+</div>
+
+
+<div class="search-navigator-header-actions">
+ {{#notNull state.total}}
+ <div class="search-navigator-header-pagination">
+ {{#gt state.total 0}}
+ <a class="js-prev icon-prev" title="{{t 'paging_previous'}}"></a>
+ <span class="current">{{sum state.selectedIndex 1}} / <span id="coding-rules-total">{{state.total}}</span></span>
+ <a class="js-next icon-next" title="{{t 'paging_next'}}"></a>
+ {{else}}
+ <span class="current">0 / <span id="coding-rules-total">0</span></span>
+ {{/gt}}
+ </div>
+ {{/notNull}}
+
+
+ <div class="search-navigator-header-buttons button-group">
+ <button class="js-reload">{{t 'reload'}}</button>
+ {{#if state.canBulkChange}}
+ <button class="js-bulk-change">{{t 'bulk_change'}}</button>
+ {{/if}}
+ </div>
+</div>
--- /dev/null
+<div class="coding-rule-inner">
+ <div class="coding-rule-title">
+ <a class="js-rule link-no-underline">{{name}}</a>
+ </div>
+ <div class="coding-rule-meta">
+ <a class="js-lang link-no-underline" data-lang="{{lang}}">{{langName}}</a>
+ {{#notEmpty sysTags}}
+
+ <i class="icon-tags"></i>
+ {{#each sysTags}}
+ <a class="js-tag link-no-underline" data-tag="{{this}}">{{this}}</a>
+ {{/each}}
+ {{/notEmpty}}
+ </div>
+</div>
--- /dev/null
+<div class="js-list"></div>
+
+<div class="search-navigator-workspace-list-more js-more">
+ <i class="spinner"></i>
+</div>
--- /dev/null
+<a class="search-navigator-facet-header js-facet-toggle">
+ <i class="icon-checkbox {{#if enabled}}icon-checkbox-checked{{/if}}"></i>
+ {{t 'coding_rules.facet' property}}
+</a>
--- /dev/null
+{{> '_coding-rules-facet-header'}}
+
+<div class="search-navigator-facet-list">
+ {{#each values}}
+ <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}">
+ <span class="facet-name">{{default label val}}{{#if extra}} <span class="subtitle">{{extra}}</span>{{/if}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/each}}
+</div>
--- /dev/null
+{{> '_coding-rules-facet-header'}}
+
+<div class="search-navigator-facet-list">
+ {{#each values}}
+ <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'severity' val}}">
+ <span class="facet-name">{{severityIcon val}} {{t 'severity' val}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/each}}
+</div>
-<a class="issues-facet-header js-issues-facet-toggle">
+<a class="search-navigator-facet-header js-facet-toggle">
<i class="icon-checkbox {{#if enabled}}icon-checkbox-checked{{/if}}"></i>
{{t 'issues.facet' property}}
</a>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
{{#eq val ''}}
{{! unplanned }}
- <a class="facet issues-facet js-issues-facet" data-unplanned title="{{t 'issue.unplanned'}}">
+ <a class="facet search-navigator-facet js-facet" data-unplanned title="{{t 'issue.unplanned'}}">
<span class="facet-name">{{t 'issue.unplanned'}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{else}}
- <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{label}}">
+ <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{label}}">
<span class="facet-name">{{label}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
{{#eq val ''}}
{{! unassigned }}
- <a class="facet issues-facet js-issues-facet" data-unassigned title="{{t 'unassigned'}}">
+ <a class="facet search-navigator-facet js-facet" data-unassigned title="{{t 'unassigned'}}">
<span class="facet-name">{{t 'unassigned'}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{else}}
- <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{label}}">
+ <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{label}}">
<span class="facet-name">{{label}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{/eq}}
{{/each}}
- <div class="issues-facet-custom-value">
- <input type="hidden" class="js-issues-custom-value">
+ <div class="search-navigator-facet-custom-value">
+ <input type="hidden" class="js-custom-value">
</div>
</div>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
- <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{default label val}}">
+ <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}">
<span class="facet-name">{{default label val}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list issues-facet-list-align-right">
+<div class="search-navigator-facet-list search-navigator-facet-list-align-right">
{{#each values}}
- <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{default label val}}">
+ <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{default label val}}">
<span class="facet-name">{{default label val}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{#if createdAt}}
<input type="hidden" name="createdAt">
- <div class="issues-facet-container">
+ <div class="search-navigator-facet-container">
{{dt createdAt}} ({{fromNow createdAt}})
</div>
{{else}}
- <div class="issues-facet-container justify">
- <input type="text" class="issues-facet-input" name="createdAfter" placeholder="From">
+ <div class="search-navigator-facet-container justify">
+ <input type="text" class="search-navigator-facet-input" name="createdAfter" placeholder="From">
to
- <input type="text" class="issues-facet-input" name="createdBefore" placeholder="To">
+ <input type="text" class="search-navigator-facet-input" name="createdBefore" placeholder="To">
</div>
{{/if}}
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
- <a class="facet issues-facet js-issues-facet" data-value="{{val}}" title="{{#if extra}}({{extra}}) {{/if}}{{default label val}}">
+ <a class="facet search-navigator-facet js-facet" data-value="{{val}}" title="{{#if extra}}({{extra}}) {{/if}}{{default label val}}">
<span class="facet-name">{{default label val}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{/each}}
- <div class="issues-facet-custom-value">
- <input type="hidden" class="js-issues-custom-value">
+ <div class="search-navigator-facet-custom-value">
+ <input type="hidden" class="js-custom-value">
</div>
</div>
{{> '_issues-facet-header'}}
-<div class="issues-facet-container">
+<div class="search-navigator-facet-container">
{{issues}}
</div>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
{{#eq val ''}}
{{! unresolved }}
- <a class="facet issues-facet issues-facet-half js-issues-facet" data-unresolved title="{{t 'unresolved'}}">
+ <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-unresolved title="{{t 'unresolved'}}">
<span class="facet-name">{{t 'unresolved'}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{else}}
- <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}" title="{{t 'issue.resolution' val}}">
+ <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'issue.resolution' val}}">
<span class="facet-name">{{t 'issue.resolution' val}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
- <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}" title="{{t 'severity' val}}">
+ <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'severity' val}}">
<span class="facet-name">{{severityIcon val}} {{t 'severity' val}}</span>
<span class="facet-stat">{{count}}</span>
</a>
{{> '_issues-facet-header'}}
-<div class="issues-facet-list">
+<div class="search-navigator-facet-list">
{{#each values}}
- <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}" title="{{t 'issue.status' val}}">
+ <a class="facet search-navigator-facet search-navigator-facet-half js-facet" data-value="{{val}}" title="{{t 'issue.status' val}}">
<span class="facet-name">{{statusIcon val}} {{t 'issue.status' val}}</span>
<span class="facet-stat">{{count}}</span>
</a>
-<div class="issues-filters-list">
+<div class="search-navigator-filters-list">
{{#each items}}
- <a class="issues-filters-button issues-filters-filter js-issues-filter" data-id="{{id}}">{{name}}</a>
+ <a class="search-navigator-filters-button search-navigator-filters-filter js-filter" data-id="{{id}}">{{name}}</a>
<br>
{{/each}}
- <a class="issues-filters-manage" href="{{link '/issues/manage'}}"><i class="icon-settings"></i> {{t 'manage'}}</a>
+ <a class="search-navigator-filters-manage" href="{{link '/issues/manage'}}"><i class="icon-settings"></i> {{t 'manage'}}</a>
</div>
-<div class="issues-filters-header">
+<div class="search-navigator-filters-header">
{{#if state.canManageFilters}}
- <a class="issues-filters-show-list js-issues-toggle-filters">
+ <a class="search-navigator-filters-show-list js-toggle-filters">
<i class="icon-list"></i> <span class="issues-filters-name">{{> '_issues-filter-name'}}</span>
</a>
{{#if filter.description}}
- <div class="issues-filters-description">{{filter.description}}</div>
+ <div class="search-navigator-filters-description">{{filter.description}}</div>
{{/if}}
{{else}}
- <span class="issues-filters-name">{{t 'issues'}}</span>
+ <span class="search-navigator-filters-name">{{t 'issues'}}</span>
{{/if}}
</div>
-<div class="issues-filters-actions">
+<div class="search-navigator-filters-actions">
<div class="button-group">
- <button id="issues-new-search">{{t 'issue_filter.new_search'}}</button>
+ <button class="js-new-search" id="issues-new-search">{{t 'issue_filter.new_search'}}</button>
{{#if state.canManageFilters}}
{{#if filter.canModify}}
- {{#if state.changed}}<button id="issues-filter-save">{{t 'save'}}</button>{{/if}}
+ {{#if state.changed}}<button class="js-filter-save" id="issues-filter-save">{{t 'save'}}</button>{{/if}}
{{/if}}
- {{#unless filter.id}}<button id="issues-filter-save-as">{{t 'save_as'}}</button>{{/unless}}
- {{#if filter.id}}<button id="issues-filter-copy">{{t 'copy'}}</button>{{/if}}
+ {{#unless filter.id}}<button class="js-filter-save-as" id="issues-filter-save-as">{{t 'save_as'}}</button>{{/unless}}
+ {{#if filter.id}}<button class="js-filter-copy" id="issues-filter-copy">{{t 'copy'}}</button>{{/if}}
{{#if filter.canModify}}
- {{#if filter.id}}<button id="issues-filter-edit">{{t 'edit'}}</button>{{/if}}
+ {{#if filter.id}}<button class="js-filter-edit" id="issues-filter-edit">{{t 'edit'}}</button>{{/if}}
{{/if}}
{{/if}}
</div>
-<div class="issues-side">
- <div class="issues-filters"></div>
- <div class="issues-facets"></div>
+<div class="search-navigator-side">
+ <div class="search-navigator-filters"></div>
+ <div class="search-navigator-facets"></div>
</div>
-<div class="issues-workspace">
- <div class="issues-workspace-header issues-header"></div>
- <div class="issues-workspace-list"></div>
+<div class="search-navigator-workspace">
+ <div class="search-navigator-workspace-header"></div>
+ <div class="search-navigator-workspace-list"></div>
<div class="issues-workspace-component-viewer"></div>
</div>
</div>
-<div class="issues-header-actions">
+<div class="search-navigator-header-actions">
{{#notNull state.total}}
- <div class="issues-header-pagination">
+ <div class="search-navigator-header-pagination">
{{#gt state.total 0}}
- <a class="js-issues-prev icon-prev" title="{{t 'paging_previous'}}"></a>
+ <a class="js-prev icon-prev" title="{{t 'paging_previous'}}"></a>
<span class="current">{{sum state.selectedIndex 1}} / <span id="issues-total">{{state.total}}</span></span>
- <a class="js-issues-next icon-next" title="{{t 'paging_next'}}"></a>
+ <a class="js-next icon-next" title="{{t 'paging_next'}}"></a>
{{else}}
<span class="current">0 / <span id="issues-total">0</span></span>
{{/gt}}
{{/notNull}}
- <div class="issues-header-buttons button-group">
- <button id="issues-reload">{{t 'reload'}}</button>
+ <div class="search-navigator-header-buttons button-group">
+ <button id="issues-reload" class="js-reload">{{t 'reload'}}</button>
{{#if state.canBulkChange}}
- <button id="issues-bulk-change">{{t 'bulk_change'}}</button>
+ <button id="issues-bulk-change" class="js-bulk-change">{{t 'bulk_change'}}</button>
{{/if}}
</div>
</div>
-<div class="js-issues-list"></div>
+<div class="js-list"></div>
-<div class="issues-workspace-list-more js-issues-more">
+<div class="search-navigator-workspace-list-more js-more">
<i class="spinner"></i>
</div>
--- /dev/null
+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();
+ });
+
+ });
--- /dev/null
+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();
+ }
+
+ });
+
+});
--- /dev/null
+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;
+ }
+ }
+
+ });
+
+ });
--- /dev/null
+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']
+ });
+
+});
--- /dev/null
+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()
+ });
+ }
+ });
+
+});
--- /dev/null
+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()
+ });
+ }
+ });
+
+});
--- /dev/null
+define([
+ 'coding-rules/facets/custom-labels-facet'
+], function (CustomLabelsFacet) {
+
+ return CustomLabelsFacet.extend({
+
+ getLabelsSource: function () {
+ return this.options.app.languages;
+ }
+
+ });
+
+});
--- /dev/null
+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()
+ });
+ }
+ });
+
+});
--- /dev/null
+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;
+ });
+ }
+
+ });
+
+});
--- /dev/null
+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())
+ });
+ }
+ });
+
+});
--- /dev/null
+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())
+ });
+ }
+ });
+
+});
--- /dev/null
+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();
+ }
+ });
+
+});
--- /dev/null
+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);
+ }
+ }
+
+ });
+
+});
--- /dev/null
+define([
+ 'backbone'
+], function (Backbone) {
+
+ return Backbone.Model.extend({
+ idAttribute: 'key'
+ });
+
+});
--- /dev/null
+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 });
+ });
+ }
+ });
+
+});
--- /dev/null
+define([
+ 'components/navigator/models/state'
+], function (State) {
+
+ return State.extend({
+ defaults: {
+ page: 1,
+ maxResultsReached: false,
+ query: {},
+ facets: []
+ }
+ });
+
+});
+
--- /dev/null
+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'))
+ });
+ }
+ });
+
+});
--- /dev/null
+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();
+ }
+ });
+
+});
--- /dev/null
+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);
+ }
+ });
+
+});
--- /dev/null
+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 });
+ }
+ });
+
+});
--- /dev/null
+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 });
+ }
+ }
+
+ });
+
+});
--- /dev/null
+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});
+ }
+
+ });
+
+});
--- /dev/null
+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())
+ });
+ }
+ });
+
+});
--- /dev/null
+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 });
+ }
+ });
+
+});
--- /dev/null
+define([
+ 'backbone',
+ 'components/navigator/models/facet'
+], function (Backbone, Facet) {
+
+ return Backbone.Collection.extend({
+ model: Facet
+ });
+
+});
--- /dev/null
+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');
+ }
+ });
+
+});
--- /dev/null
+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);
+ }
+ });
+
+});
--- /dev/null
+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()
+ });
+ }
+ });
+
+});
--- /dev/null
+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') });
+ }
+
+ });
+
+});
--- /dev/null
+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);
+ }
+ }
+
+ });
+
+});
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');
});
})
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
@import "components/modals";
@import "components/issues";
@import "components/measures";
+@import "components/rules";
+@import "components/search-navigator";
--- /dev/null
+@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: "";
+ }
+}
--- /dev/null
+@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;
+ }
+}
&.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;
}
.issues-extended-view {
- .issues-workspace-list {
+ .search-navigator-workspace-list {
display: none;
}
}
-.issues-no-results {
- padding-top: 10%;
- color: @secondFontColor;
- text-align: center;
-}
-
.code-issue-modern {
outline: 1px solid @barBorderColor;
border-left: 2px solid transparent;
--- /dev/null
+#
+# 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
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
<% end %>
-<div id="coding-rules-page-loader" class="navigator-page-loader">
- <i class="spinner"></i>
-</div>
+<div class="coding-rules search-navigator"></div>
--- /dev/null
+<% content_for :script do %>
+ <script data-main="<%= ApplicationController.root_context -%>/js/coding-rules-old/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
+<% end %>
+
+
+<div id="coding-rules-page-loader" class="navigator-page-loader">
+ <i class="spinner"></i>
+</div>
<script data-main="<%= ApplicationController.root_context -%>/js/issues/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
<% end %>
-<div class="issues"></div>
+<div class="issues search-navigator"></div>
<a href="<%= ApplicationController.root_context -%>/issues/index" class="<%= 'selected' if selected_section==Navigation::SECTION_ISSUES -%>"><%= message('issues.page') -%></a>
</li>
<li>
- <a href="<%= ApplicationController.root_context -%>/coding_rules" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES -%>"><%= message('coding_rules.page') -%></a>
+ <a href="<%= ApplicationController.root_context -%>/coding_rules" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES -%>">NEW <%= message('coding_rules.page') -%></a>
+ </li>
+ <li>
+ <a href="<%= ApplicationController.root_context -%>/coding_rules_old" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES_OLD -%>"><%= message('coding_rules.page') -%></a>
</li>
<li>
<a href="<%= ApplicationController.root_context -%>/profiles" class="<%= 'selected' if selected_section==Navigation::SECTION_QUALITY_PROFILES -%>"><%= message('quality_profiles.page') -%></a>
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
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
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