'<%= pkg.assets %>js/templates/issues.js': [
'<%= pkg.sources %>hbs/issues/**/*.hbs'
]
+ '<%= pkg.assets %>js/templates/issues-old.js': [
+ '<%= pkg.sources %>hbs/issues-old/**/*.hbs'
+ ]
'<%= pkg.assets %>js/templates/api-documentation.js': [
'<%= pkg.sources %>hbs/api-documentation/**/*.hbs'
]
ui:
facets: '.navigator-facets-list-item'
- options: '.navigator-facets-list-item-option'
+ options: '.facet'
events:
property = jQuery(@).data 'property'
if !!params[property]
_(params[property].split(',')).map (value) ->
- jQuery('.navigator-facets-list-item[data-property="' + property + '"] .navigator-facets-list-item-option[data-key="' + value + '"]').addClass 'active'
+ jQuery('.navigator-facets-list-item[data-property="' + property + '"] .facet[data-key="' + value + '"]').addClass 'active'
--- /dev/null
+define [
+ 'backbone'
+ 'issue/models/issue'
+], (
+ Backbone
+ Issue
+) ->
+
+ class extends Backbone.Collection
+ model: Issue
+
+ url: ->
+ "#{baseUrl}/api/issues/search"
+
+
+ parse: (r) ->
+ find = (source, key, keyField) ->
+ searchDict = {}
+ searchDict[keyField || 'key'] = key
+ _.findWhere(source, searchDict) || key
+
+ @paging =
+ p: r.p
+ ps: r.ps
+ total: r.total
+ maxResultsReached: r.p * r.ps >= r.total
+
+ r.issues.map (issue) ->
+ component = find r.components, issue.component
+ project = find r.projects, issue.project
+ rule = find r.rules, issue.rule
+
+ if component
+ _.extend issue,
+ componentLongName: component.longName
+ componentQualifier: component.qualifier
+
+ if project
+ _.extend issue,
+ projectLongName: project.longName
+
+ if rule
+ _.extend issue,
+ ruleName: rule.name
+
+ issue
class IssueView extends Marionette.Layout
- className: 'code-issues'
template: Templates['issue']
--- /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'
+
+ 'issues/models/state'
+ 'issues/layout'
+ 'issues/models/issues'
+ 'issues/models/facets'
+ 'issues/models/filters'
+
+ 'issues/controller'
+ 'issues/router'
+
+ 'issues/workspace-list-view'
+ 'issues/workspace-header-view'
+
+ 'issues/facets-view'
+ 'issues/filters-view'
+
+ 'common/handlebars-extensions'
+], (
+ Backbone, Marionette
+
+ State
+ Layout
+ Issues
+ Facets
+ Filters
+
+ Controller
+ Router
+
+ WorkspaceListView
+ WorkspaceHeaderView
+
+ FacetsView
+ FiltersView
+) ->
+
+ $ = jQuery
+ App = new Marionette.Application
+
+
+ App.addInitializer ->
+ @layout = new Layout()
+ $('.issues').empty().append @layout.render().el
+
+
+ App.addInitializer ->
+ @state = new State()
+ @issues = new Issues()
+ @facets = new Facets()
+ @filters = new Filters()
+
+
+ App.addInitializer ->
+ @controller = new Controller app: @
+
+
+ App.addInitializer ->
+ @controller.fetchFilters()
+
+
+ App.addInitializer ->
+ @issuesView = new WorkspaceListView
+ app: @
+ collection: @issues
+ @layout.workspaceListRegion.show @issuesView
+ @issuesView.bindScrollEvents()
+
+
+ App.addInitializer ->
+ @workspaceHeaderView = new WorkspaceHeaderView
+ app: @
+ collection: @issues
+ @layout.workspaceHeaderRegion.show @workspaceHeaderView
+
+
+ App.addInitializer ->
+ @facetsView = new FacetsView
+ app: @
+ collection: @facets
+ @layout.facetsRegion.show @facetsView
+
+
+ App.addInitializer ->
+ @filtersView = new FiltersView
+ app: @
+ collection: @filters
+ @layout.filtersRegion.show @filtersView
+
+
+ App.addInitializer ->
+ key.setScope 'list'
+ @router = new Router app: @
+ Backbone.history.start()
+
+
+ l10nXHR = window.requestMessages()
+ jQuery.when(l10nXHR).done -> App.start()
--- /dev/null
+define [
+ 'backbone'
+ 'backbone.marionette'
+ 'templates/issues'
+ 'issues/models/issues'
+ 'issues/issue-view'
+], (
+ Backbone
+ Marionette
+ Templates
+ Issues
+ IssueView
+) ->
+
+ $ = jQuery
+
+ API_SOURCES = "#{baseUrl}/api/sources/show"
+ LINES_AROUND = 500
+
+
+ class extends Marionette.ItemView
+ template: Templates['issues-component-viewer']
+
+
+ ui:
+ sourceBeforeSpinner: '.js-component-viewer-source-before'
+ sourceAfterSpinner: '.js-component-viewer-source-after'
+
+
+ events:
+ 'click .js-close-component-viewer': 'closeComponentViewer'
+
+
+ initialize: (options) ->
+ @source = new Backbone.Model
+ source: []
+ formattedSource: []
+ @component = new Backbone.Model()
+ @issues = new Issues()
+ @listenTo @issues, 'add', @addIssue
+ @listenTo options.app.state, 'change:selectedIndex', @select
+ @bindShortcuts()
+ @loadSourceBeforeThrottled = _.throttle @loadSourceBefore, 1000
+ @loadSourceAfterThrottled = _.throttle @loadSourceAfter, 1000
+
+
+ bindShortcuts: ->
+ key 'delete,backspace', 'componentViewer', =>
+ @options.app.controller.closeComponentViewer()
+ false
+
+
+ bindScrollEvents: ->
+ $(window).on 'scroll.issues-component-viewer', (=> @onScroll())
+
+
+ unbindScrollEvents: ->
+ $(window).off 'scroll.issues-component-viewer'
+
+
+ onScroll: ->
+ if @model.get('hasSourceBefore') && $(window).scrollTop() <= @ui.sourceBeforeSpinner.offset().top
+ @loadSourceBeforeThrottled()
+
+ if @model.get('hasSourceAfter') && $(window).scrollTop() + $(window).height() >= @ui.sourceAfterSpinner.offset().top
+ @loadSourceAfterThrottled()
+
+
+ loadSourceBefore: ->
+ @unbindScrollEvents()
+ formattedSource = @source.get 'formattedSource'
+ firstLine = _.first(formattedSource).lineNumber
+ @requestSources(firstLine - LINES_AROUND, firstLine - 1).done (data) =>
+ newFormattedSource = _.map data.sources, (item) => lineNumber: item[0], code: item[1]
+ formattedSource = newFormattedSource.concat formattedSource
+ @source.set formattedSource: formattedSource
+ @model.set hasSourceBefore: newFormattedSource.length == LINES_AROUND
+ @render()
+ @scrollToLine firstLine
+ @bindScrollEvents() if @model.get('hasSourceBefore') || @model.get('hasSourceAfter')
+
+
+ loadSourceAfter: ->
+ @unbindScrollEvents()
+ formattedSource = @source.get 'formattedSource'
+ lastLine = _.last(formattedSource).lineNumber
+ @requestSources(lastLine + 1, lastLine + LINES_AROUND)
+ .done (data) =>
+ newFormattedSource = _.map data.sources, (item) => lineNumber: item[0], code: item[1]
+ formattedSource = formattedSource.concat newFormattedSource
+ @source.set formattedSource: formattedSource
+ @model.set hasSourceAfter: newFormattedSource.length == LINES_AROUND
+ @render()
+ @bindScrollEvents() if @model.get('hasSourceBefore') || @model.get('hasSourceAfter')
+ .fail =>
+ @source.set formattedSource: []
+ @model.set hasSourceAfter: false
+ @render()
+
+
+ onRender: ->
+ @renderIssues()
+
+
+ renderIssues: ->
+ @issues.forEach (issue) =>
+ @renderIssue issue
+
+
+ addIssue: (issue) ->
+ @renderIssue issue
+
+
+ renderIssue: (issue) ->
+ line = issue.get 'line' || 0
+ row = @$("[data-line-number=#{line}]")
+ issueView = new IssueView model: issue
+ if row.length == 0
+ issueView.render().$el.insertBefore @$('.issues-workspace-component-viewer-code')
+ else
+ row.find('.line').addClass 'issue'
+ barRow = $('<tr></tr>').insertAfter row
+ barCell = $('<td colspan="2"></td>').appendTo barRow
+ issueView.render().$el.appendTo barCell
+
+
+ select: ->
+ selected = @options.app.state.get 'selectedIndex'
+ selectedKey = @options.app.issues.at(selected).get 'key'
+ @highlightIssue selectedKey
+
+
+ highlightIssue: (key) ->
+ @$("[data-issue-key]").removeClass 'highlighted'
+ @$("[data-issue-key='#{key}']").addClass 'highlighted'
+
+
+ openFileByIssue: (issue) ->
+ componentKey = issue.get 'component'
+ @issues.reset @options.app.issues.filter (issue) => issue.get('component') == componentKey
+
+ line = issue.get('line') || 0
+ @model.set key: componentKey, issueLine: line
+
+ @requestSources(line - LINES_AROUND, line + LINES_AROUND).done (data) =>
+ formattedSource = _.map data.sources, (item) => lineNumber: item[0], code: item[1]
+ @source.set
+ source: data.sources
+ formattedSource: formattedSource
+ @model.set hasSourceBefore: line > LINES_AROUND
+ @render()
+ @highlightIssue issue.get 'key'
+ @scrollToLine issue.get 'line'
+ @bindScrollEvents()
+ @requestIssues()
+
+
+ requestSources: (lineFrom, lineTo) ->
+ lineFrom = Math.max 0, lineFrom
+ $.get API_SOURCES, key: @model.get('key'), from: lineFrom, to: lineTo
+
+
+ requestIssues: ->
+ lastIssue = @options.app.issues.at @options.app.issues.length - 1
+ lastLine = _.last(@source.get('formattedSource')).lineNumber
+ needMore = lastIssue.get('component') == @model.get 'key'
+ needMore = needMore && (lastIssue.get('line') <= lastLine)
+ if needMore
+ @options.app.controller.fetchNextPage().done =>
+ @addNextIssuesPage()
+ @requestIssues()
+
+
+ addNextIssuesPage: ->
+ componentKey = @model.get 'key'
+ @issues.add @options.app.issues.filter (issue) => issue.get('component') == componentKey
+
+
+ scrollToLine: (line) ->
+ row = @$("[data-line-number=#{line}]")
+ goal = if row.length > 0 then row.offset().top - 40 else 0
+ $(window).scrollTop goal
+
+
+ closeComponentViewer: ->
+ @options.app.controller.closeComponentViewer()
+
+
+ serializeData: ->
+ _.extend super,
+ source: @source.get 'formattedSource'
--- /dev/null
+define [
+ 'backbone'
+], (
+ Backbone
+) ->
+
+ class extends Backbone.Model
+
+ defaults:
+ hasSourceBefore: true
+ hasSourceAfter: true
+
--- /dev/null
+define [
+ 'backbone.marionette'
+
+ 'issues/component-viewer/main'
+ 'issues/component-viewer/state'
+], (
+ Marionette
+
+ ComponentViewer
+ ComponentViewerState
+) ->
+
+ $ = jQuery
+ EXTRA_FIELDS = 'actions,transitions,assigneeName,reporterName,actionPlanName'
+ PAGE_SIZE = 50
+
+
+ class extends Marionette.Controller
+
+ initialize: (options) ->
+ @listenTo options.app.state, 'change:query', @fetchIssues
+
+
+ _issuesParameters: ->
+ p: @options.app.state.get 'page'
+ ps: PAGE_SIZE
+ s: 'FILE_LINE'
+ asc: true
+ extra_fields: EXTRA_FIELDS
+ facets: @options.app.state.get('facets').join()
+
+
+ _allFacets: ->
+ @options.app.state.get('allFacets').map (facet) -> { property: facet }
+
+
+ fetchIssues: (firstPage = true) ->
+ if firstPage
+ @options.app.state.set { selectedIndex: 0, page: 1 }, { silent: true }
+
+ data = @_issuesParameters()
+ _.extend data, @options.app.state.get 'query'
+
+ fetchIssuesProcess = window.process.addBackgroundProcess()
+ $.get "#{baseUrl}/api/issues/search", data, (r) =>
+ issues = @options.app.issues.parseIssues r
+ if firstPage
+ @options.app.issues.reset issues
+ else
+ @options.app.issues.add issues
+
+ _.extend @options.app.facets,
+ components: r.components
+ projects: r.projects
+ rules: r.rules
+ users: r.users
+ actionPlans: r.actionPlans
+ @options.app.facets.reset @_allFacets()
+ @options.app.facets.add r.facets, merge: true
+ @enableFacets @options.app.state.get 'facets'
+
+ @options.app.state.set
+ page: r.p
+ pageSize: r.ps
+ total: r.total
+ maxResultsReached: r.p * r.ps >= r.total
+
+ window.process.finishBackgroundProcess fetchIssuesProcess
+
+
+ fetchNextPage: ->
+ @options.app.state.nextPage()
+ @fetchIssues false
+
+
+ fetchFilters: ->
+ $.get "#{baseUrl}/api/issue_filters/app", (r) =>
+ @options.app.state.set
+ canBulkChange: r.canBulkChange
+ canManageFilters: r.canManageFilters
+ @options.app.filters.reset r.favorites
+
+
+ enableFacet: (facet) ->
+ @options.app.facets.get(facet).set enabled: true
+
+
+ enableFacets: (facets) ->
+ facets.forEach @enableFacet, @
+
+
+ newSearch: ->
+ @options.app.state.unset 'filter'
+ @options.app.state.setQuery resolved: 'false'
+
+
+ applyFilter: (filter) ->
+ query = @parseQuery filter.get 'query'
+ @options.app.state.setQuery query
+ @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]
+ q
+
+
+ getQuery: (separator = '|') ->
+ filter = @options.app.state.get 'query'
+ route = []
+ _.map filter, (value, property) ->
+ route.push "#{property}=#{decodeURIComponent value}"
+ route.join separator
+
+
+ _prepareComponent: (issue) ->
+ key: issue.get 'component'
+ name: issue.get 'componentLongName'
+ qualifier: issue.get 'componentQualifier'
+ project: issue.get 'project'
+ projectName: issue.get 'projectLongName'
+
+
+ showComponentViewer: (issue) ->
+ key.setScope 'componentViewer'
+ @options.app.issuesView.unbindScrollEvents()
+ @options.app.state.set 'component', @_prepareComponent(issue)
+ @options.app.componentViewer = new ComponentViewer
+ app: @options.app
+ model: new ComponentViewerState()
+ @options.app.layout.workspaceComponentViewerRegion.show @options.app.componentViewer
+ @options.app.layout.showComponentViewer()
+ @options.app.componentViewer.openFileByIssue issue
+
+
+ closeComponentViewer: ->
+ key.setScope 'list'
+ @options.app.state.unset 'component'
+ @options.app.componentViewer.unbindScrollEvents()
+ @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
+
+
+ selectPreviousIssue: ->
+ index = @options.app.state.get('selectedIndex') - 1
+ if index >= 0
+ @options.app.state.set selectedIndex: index
--- /dev/null
+define [
+ 'backbone.marionette'
+
+ 'issues/facets/base-facet'
+ 'issues/facets/severity-facet'
+ 'issues/facets/status-facet'
+ 'issues/facets/project-facet'
+ 'issues/facets/assignee-facet'
+ 'issues/facets/rule-facet'
+ 'issues/facets/resolution-facet'
+ 'issues/facets/creation-date-facet'
+], (
+ Marionette
+ BaseFacet
+ SeverityFacet
+ StatusFacet
+ ProjectFacet
+ AssigneeFacet
+ RuleFacet
+ ResolutionFacet
+ CreationDateFacet
+) ->
+
+ class extends Marionette.CollectionView
+ className: 'issues-facets-list'
+
+
+ getItemView: (model) ->
+ switch model.get 'property'
+ when 'severities' then SeverityFacet
+ when 'statuses' then StatusFacet
+ when 'assignees' then AssigneeFacet
+ when 'resolutions' then ResolutionFacet
+ when 'created' then CreationDateFacet
+ when 'componentRootUuids' then ProjectFacet
+ when 'rules' then RuleFacet
+ when 'creationDate' then CreationDateFacet
+ else BaseFacet
+
+
+ itemViewOptions: ->
+ app: @options.app
+
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+ 'templates/issues'
+], (
+ BaseFacet
+ Templates
+) ->
+
+ $ = jQuery
+
+
+ class extends BaseFacet
+ template: Templates['issues-assignee-facet']
+
+
+ onRender: ->
+ super
+
+ value = @options.app.state.get('query')['assigned']
+ if value? && (!value || value == 'false')
+ @$('.js-issues-facet').filter("[data-unassigned]").addClass 'active'
+
+
+ toggleFacet: (e) ->
+ unassigned = $(e.currentTarget).is "[data-unassigned]"
+ if unassigned
+ $(e.currentTarget).toggleClass 'active'
+ checked = $(e.currentTarget).is '.active'
+ if checked
+ @options.app.state.updateFilter assigned: 'false', assignees: null
+ else
+ @options.app.state.updateFilter assigned: null, assignees: null
+ else
+ super
+
+
+ getValuesWithLabels: ->
+ values = @model.getValues()
+ users = @options.app.facets.users
+ values.forEach (v) =>
+ login = v.val
+ name = ''
+ if login
+ user = _.findWhere users, login: login
+ name = user.name if user?
+ v.label = name
+ values
+
+
+ serializeData: ->
+ _.extend super,
+ values: @getValuesWithLabels()
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/issues'
+], (
+ Marionette
+ Templates
+) ->
+
+ $ = jQuery
+
+
+ class extends Marionette.ItemView
+ className: 'issues-facet-box'
+ template: Templates['issues-base-facet']
+
+
+ modelEvents: ->
+ 'change': 'render'
+
+
+ events: ->
+ 'click .js-issues-facet-toggle': 'toggle'
+ 'click .js-issues-facet': 'toggleFacet'
+
+
+ onRender: ->
+ console.log @model.id, @model.get 'enabled'
+ @$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) =>
+ @$('.js-issues-facet').filter("[data-value='#{s}']").addClass 'active'
+
+
+ toggle: ->
+ @model.toggle()
+
+
+ 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
+
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+ 'templates/issues'
+], (
+ BaseFacet
+ Templates
+) ->
+
+ $ = jQuery
+
+
+ class extends BaseFacet
+ template: Templates['issues-creation-date-facet']
+
+
+ events: ->
+ _.extend super,
+ 'change input': 'applyFacet'
+
+
+ onRender: ->
+ @$el.toggleClass 'issues-facet-box-collapsed', !@model.get('enabled')
+
+ @$('input').datepicker
+ dateFormat: 'yy-mm-dd'
+ changeMonth: true
+ changeYear: true
+
+ props = ['createdAfter', 'createdBefore', 'createdAt']
+ query = @options.app.state.get 'query'
+ props.forEach (prop) =>
+ value = query[prop]
+ @$("input[name=#{prop}]").val value if value?
+
+
+ applyFacet: ->
+ obj = {}
+ @$('input').each ->
+ property = $(@).prop 'name'
+ value = $(@).val()
+ obj[property] = value
+ @options.app.state.updateFilter obj
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+], (
+ BaseFacet
+) ->
+
+
+ class extends BaseFacet
+
+ getValuesWithLabels: ->
+ values = @model.getValues()
+ projects = @options.app.facets.projects
+ values.forEach (v) =>
+ uuid = v.val
+ label = ''
+ if uuid
+ project = _.findWhere projects, uuid: uuid
+ label = project.longName if project?
+ v.label = label
+ values
+
+
+ serializeData: ->
+ _.extend super,
+ values: @getValuesWithLabels()
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+ 'templates/issues'
+], (
+ BaseFacet
+ Templates
+) ->
+
+ $ = jQuery
+
+
+ class extends BaseFacet
+ template: Templates['issues-resolution-facet']
+
+
+ onRender: ->
+ super
+
+ value = @options.app.state.get('query')['resolved']
+ if value? && (!value || value == 'false')
+ @$('.js-issues-facet').filter("[data-unresolved]").addClass 'active'
+
+
+ toggleFacet: (e) ->
+ unresolved = $(e.currentTarget).is "[data-unresolved]"
+ $(e.currentTarget).toggleClass 'active'
+ if unresolved
+ checked = $(e.currentTarget).is '.active'
+ value = if checked then 'false' else null
+ @options.app.state.updateFilter resolved: value, resolutions: null
+ else
+ @options.app.state.updateFilter resolved: null, resolutions: @getValue()
+
+
+ sortValues: (values) ->
+ order = ['FIXED', 'FALSE-POSITIVE', 'CLOSED']
+ _.sortBy values, (v) -> order.indexOf v.val
+
+
+ serializeData: ->
+ _.extend super,
+ values: @sortValues @model.getValues()
+
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+], (
+ BaseFacet
+) ->
+
+
+ class extends BaseFacet
+
+ getValuesWithLabels: ->
+ values = @model.getValues()
+ rules = @options.app.facets.rules
+ values.forEach (v) =>
+ key = v.val
+ label = ''
+ if key
+ rule = _.findWhere rules, key: key
+ label = rule.name if rule?
+ v.label = label
+ values
+
+
+ serializeData: ->
+ _.extend super,
+ values: @getValuesWithLabels()
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+ 'templates/issues'
+], (
+ BaseFacet
+ Templates
+) ->
+
+
+ class extends BaseFacet
+ template: Templates['issues-severity-facet']
+
+
+ sortValues: (values) ->
+ order = ['BLOCKER', 'MINOR', 'CRITICAL', 'INFO', 'MAJOR']
+ _.sortBy values, (v) -> order.indexOf v.val
+
+
+ serializeData: ->
+ _.extend super,
+ values: @sortValues @model.getValues()
+
--- /dev/null
+define [
+ 'issues/facets/base-facet'
+ 'templates/issues'
+], (
+ BaseFacet
+ Templates
+) ->
+
+
+ class extends BaseFacet
+ template: Templates['issues-status-facet']
+
+
+ sortValues: (values) ->
+ order = ['OPEN', 'RESOLVED', 'REOPENED', 'CLOSED', 'CONFIRMED']
+ _.sortBy values, (v) -> order.indexOf v.val
+
+
+ serializeData: ->
+ _.extend super,
+ values: @sortValues @model.getValues()
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/issues'
+], (
+ Marionette
+ Templates
+) ->
+
+ $ = jQuery
+
+
+ class extends Marionette.ItemView
+ template: Templates['issues-filters']
+
+
+ events:
+ 'click .js-issues-toggle-filters': 'toggleFilters'
+ 'click .js-issues-filter': 'applyFilter'
+ 'click .js-issues-new-search': 'newSearch'
+ 'click .js-issues-save-as': 'saveAs'
+ 'click .js-issues-save': 'save'
+ 'click .js-issues-copy': 'copy'
+ 'click .js-issues-edit': 'edit'
+
+
+ initialize: (options) ->
+ @listenTo options.app.state, 'change:filter', @render
+ @listenTo options.app.state, 'change:changed', @render
+ @listenTo options.app.filters, 'all', @render
+ window.onSaveAs = window.onCopy = window.onEdit = (id) =>
+ $('#modal').dialog 'close'
+ @options.app.controller.fetchFilters().done =>
+ filter = @collection.get id
+ filter.fetch().done => @options.app.controller.applyFilter filter
+
+
+ toggleFilters: ->
+ @$('.issues-filters-list').toggle()
+
+
+ applyFilter: (e) ->
+ id = $(e.currentTarget).data 'id'
+ filter = @collection.get id
+ filter.fetch().done => @options.app.controller.applyFilter filter
+
+
+ newSearch: ->
+ @options.app.controller.newSearch()
+
+
+ saveAs: ->
+ query = @options.app.controller.getQuery '&'
+ url = "#{baseUrl}/issues/save_as_form?#{query}"
+ openModalWindow url, {}
+
+
+ save: ->
+ query = @options.app.controller.getQuery '&'
+ url = "#{baseUrl}/issues/save/#{@options.app.state.get('filter').id}?#{query}"
+ $.post(url).done =>
+ @options.app.state.set changed: false
+
+
+ copy: ->
+ url = "#{baseUrl}/issues/copy_form/#{@options.app.state.get('filter').id}"
+ openModalWindow url, {}
+
+
+ edit: ->
+ url = "#{baseUrl}/issues/edit_form/#{@options.app.state.get('filter').id}"
+ openModalWindow url, {}
+
+
+ serializeData: ->
+ _.extend super,
+ state: @options.app.state.toJSON()
+ filter: @options.app.state.get('filter')?.toJSON()
--- /dev/null
+define [
+ 'issue/issue-view'
+ 'templates/issues'
+], (
+ IssueView
+ Templates
+) ->
+
+
+ class extends IssueView
+ template: Templates['issues-issue']
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/issues'
+], (
+ Marionette
+ Templates
+) ->
+
+ $ = jQuery
+
+ # http://stackoverflow.com/questions/7600454/how-to-prevent-page-scrolling-when-scrolling-a-div-element
+ $.fn.isolatedScroll = ->
+ @on 'mousewheel DOMMouseScroll', (e) ->
+ delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail
+ bottomOverflow = @scrollTop + $(@).outerHeight() - @scrollHeight >= 0
+ topOverflow = @scrollTop <= 0
+ e.preventDefault() if (delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)
+ @
+
+
+ class extends Marionette.Layout
+ template: Templates['issues-layout']
+
+
+ regions:
+ filtersRegion: '.issues-filters'
+ facetsRegion: '.issues-facets'
+ workspaceHeaderRegion: '.issues-workspace-header'
+ workspaceListRegion: '.issues-workspace-list'
+ workspaceComponentViewerRegion: '.issues-workspace-component-viewer'
+
+
+ initialize: ->
+ $(window).on 'scroll.issues-layout', (=> @onScroll())
+
+
+ onClose: ->
+ $(window).off 'scroll.issues-layout'
+
+
+ onRender: ->
+ @$('.issues-side').isolatedScroll()
+
+
+ onScroll: ->
+ scrollTop = $(window).scrollTop()
+ $('.issues').toggleClass 'sticky', scrollTop >= 30
+ @$('.issues-side').css top: Math.max(0, Math.min(30 - scrollTop, 30))
+
+
+ showSpinner: (region) ->
+ @[region].show new Marionette.ItemView
+ template: _.template('<i class="spinner"></i>')
+
+
+ showComponentViewer: ->
+ @scroll = $(window).scrollTop()
+ $('.issues').addClass 'issues-extended-view'
+
+
+ hideComponentViewer: ->
+ $('.issues').removeClass 'issues-extended-view'
+ $(window).scrollTop @scroll if @scroll?
--- /dev/null
+define [
+ 'backbone'
+], (
+ Backbone
+) ->
+
+ class extends Backbone.Model
+ idAttribute: 'property'
+
+
+ defaults:
+ enabled: false
+
+
+ getValues: ->
+ console.log @toJSON()
+ @get('values') || []
+
+
+ toggle: ->
+ enabled = @get 'enabled'
+ @set enabled: !enabled
--- /dev/null
+define [
+ 'backbone'
+ 'issues/models/facet'
+], (
+ Backbone
+ Facet
+) ->
+
+ class extends Backbone.Collection
+ model: Facet
--- /dev/null
+define [
+ 'backbone'
+], (
+ Backbone
+) ->
+
+ class extends Backbone.Model
+
+ url: ->
+ "/api/issue_filters/show/#{@id}"
+
+
+ parse: (r) ->
+ if r.filter? then r.filter else r
--- /dev/null
+define [
+ 'backbone'
+ 'issues/models/filter'
+], (
+ Backbone
+ Filter
+) ->
+
+ class extends Backbone.Collection
+ model: Filter
--- /dev/null
+define [
+ 'backbone'
+ 'issue/models/issue'
+], (
+ Backbone
+ Issue
+) ->
+
+ class extends Backbone.Collection
+ model: Issue
+
+ url: ->
+ "#{baseUrl}/api/issues/search"
+
+
+ # Used to parse /api/issues/search response
+ parseIssues: (r) ->
+ find = (source, key, keyField) ->
+ searchDict = {}
+ searchDict[keyField || 'key'] = key
+ _.findWhere(source, searchDict) || key
+
+ r.issues.map (issue) ->
+ component = find r.components, issue.component
+ project = find r.projects, issue.project
+ rule = find r.rules, issue.rule
+
+ if component
+ _.extend issue,
+ componentLongName: component.longName
+ componentQualifier: component.qualifier
+
+ if project
+ _.extend issue,
+ projectLongName: project.longName
+
+ if rule
+ _.extend issue,
+ ruleName: rule.name
+
+ if _.isArray(issue.sources) && issue.sources.length > 0
+ source = ''
+ issue.sources.forEach (line) ->
+ source = line[1] if line[0] == issue.line
+ _.extend issue, source: source
+
+
+ if _.isArray(issue.scm) && issue.scm.length > 0
+ scmAuthor = ''
+ scmDate = ''
+
+ issue.scm.forEach (line) ->
+ if line[0] == issue.line
+ scmAuthor = line[1]
+ scmDate = line[2]
+
+ _.extend issue,
+ scmAuthor: scmAuthor
+ scmDate: scmDate
+
+ issue
--- /dev/null
+define [
+ 'backbone'
+], (
+ Backbone
+) ->
+
+ class extends Backbone.Model
+
+ defaults:
+ page: 1
+ maxResultsReached: false
+
+ query: {}
+
+ facets: ['severities', 'statuses', 'resolutions', 'componentRootUuids']
+ allFacets: ['severities', 'statuses', 'resolutions', 'componentRootUuids', 'assignees', 'reporters', 'rule',
+ 'languages', 'actionPlan', 'creationDate']
+
+
+ nextPage: ->
+ page = @get 'page'
+ @set page: page + 1
+
+
+ cleanQuery: (query) ->
+ q = {}
+ Object.keys(query).forEach (key) ->
+ q[key] = query[key] if query[key]
+ q
+
+
+ updateFilter: (obj) ->
+ filter = @get 'query'
+ _.extend filter, obj
+ @setQuery @cleanQuery filter
+
+
+ setQuery: (query) ->
+ @set { query: query }, { silent: true }
+ @trigger 'change:query'
+ @set changed: true
+
--- /dev/null
+define [
+ 'backbone'
+], (
+ Backbone
+) ->
+
+ class extends Backbone.Router
+ routeSeparator: '|'
+
+ routes:
+ '': 'emptyQuery'
+ ':query': 'index'
+
+
+ initialize: (options) ->
+ @options = options
+ @listenTo @options.app.state, 'change:query', @updateRoute
+
+
+ emptyQuery: ->
+ @navigate 'resolved=false', { trigger: true, replace: true }
+
+
+ index: (query) ->
+ filter = @options.app.controller.parseQuery query
+ @options.app.state.setQuery filter
+
+
+ updateRoute: ->
+ route = @options.app.controller.getQuery()
+ @navigate route
+
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/issues'
+], (
+ Marionette
+ Templates
+) ->
+
+ $ = jQuery
+
+
+ class extends Marionette.ItemView
+ template: Templates['issues-workspace-header']
+
+
+ collectionEvents:
+ 'all': 'render'
+
+
+ events:
+ 'click .js-back': 'returnToList'
+ 'click .js-issues-bulk-change': 'bulkChange'
+ 'click .js-issues-next': 'selectNextIssue'
+ 'click .js-issues-prev': 'selectPrevIssue'
+
+
+ initialize: (options) ->
+ @listenTo options.app.state, 'change', @render
+ @_onBulkIssues = window.onBulkIssues
+ window.onBulkIssues = =>
+ $('#modal').dialog 'close'
+ @options.app.controller.fetchIssues()
+ @bindShortcuts()
+
+
+ onClose: ->
+ window.onBulkIssues = @_onBulkIssues
+
+
+ returnToList: ->
+ @options.app.controller.closeComponentViewer()
+
+
+ bulkChange: ->
+ query = @options.app.controller.getQuery '&'
+ url = "#{baseUrl}/issues/bulk_change_form?#{query}"
+ openModalWindow url, {}
+
+
+ selectNextIssue: ->
+ @options.app.controller.selectNextIssue()
+
+
+ selectPrevIssue: ->
+ @options.app.controller.selectPreviousIssue()
+
+
+ bindShortcuts: ->
+ key 'j,up', =>
+ @options.app.controller.selectPreviousIssue()
+ false
+ key 'k,down', =>
+ @options.app.controller.selectNextIssue()
+ false
+
+
+ serializeData: ->
+ _.extend super,
+ state: @options.app.state.toJSON()
+
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/issues'
+ 'issues/issue-view'
+], (
+ Marionette
+ Templates
+ IssueBoxView
+) ->
+
+ class extends Marionette.ItemView
+ tagName: 'li'
+ className: 'issue-box'
+ template: Templates['issues-workspace-list-item']
+
+
+ events:
+ 'click .js-issues-snippet': 'openComponentViewer'
+
+
+ initialize: (options) ->
+ @listenTo options.app.state, 'change:selectedIndex', @select
+
+
+ onRender: ->
+ @issueBoxView = new IssueBoxView model: @model
+ @$('.issue-box-details').append @issueBoxView.render().el
+ @select()
+
+
+ select: ->
+ selected = @options.index == @options.app.state.get 'selectedIndex'
+ @$el.toggleClass 'selected', selected
+
+
+ onClose: ->
+ @issueBoxView?.close()
+
+
+ openComponentViewer: ->
+ @options.app.state.set selectedIndex: @options.index
+ @options.app.controller.showComponentViewer @model
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/issues'
+ 'issues/workspace-list-item-view'
+], (
+ Marionette
+ Templates
+ IssueView
+) ->
+
+ $ = jQuery
+
+ TOP_OFFSET = 38
+ BOTTOM_OFFSET = 10
+
+
+ class extends Marionette.CompositeView
+ template: Templates['issues-workspace-list']
+ itemView: IssueView
+ itemViewContainer: 'ul'
+
+
+ ui:
+ loadMore: '.js-issues-more'
+
+
+ itemViewOptions: (_, index) ->
+ app: @options.app
+ index: index
+
+
+ collectionEvents:
+ 'reset': 'scrollToTop'
+
+
+ initialize: ->
+ @loadMoreThrottled = _.throttle @loadMore, 1000
+ @listenTo @options.app.state, 'change:maxResultsReached', @toggleLoadMore
+ @listenTo @options.app.state, 'change:selectedIndex', @scrollToIssue
+ @bindShortcuts()
+
+
+ onClose: ->
+ @unbindScrollEvents()
+
+
+ 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: ->
+ key 'return', 'list', =>
+ selectedIssue = @collection.at @options.app.state.get 'selectedIndex'
+ @options.app.controller.showComponentViewer selectedIssue
+ return false
+
+
+ loadMore: ->
+ unless @options.app.state.get 'maxResultsReached'
+ @unbindScrollEvents()
+ @options.app.controller.fetchNextPage().done => @bindScrollEvents()
+
+
+ onScroll: ->
+ if $(window).scrollTop() + $(window).height() >= @ui.loadMore.offset().top
+ @loadMoreThrottled()
+
+
+ scrollToTop: ->
+ @$el.scrollParent().scrollTop 0
+
+
+ scrollToIssue: ->
+ selectedIssue = @collection.at @options.app.state.get 'selectedIndex'
+ selectedIssueView = @children.findByModel selectedIssue
+ viewTop = selectedIssueView.$el.offset().top
+ viewBottom = viewTop + selectedIssueView.$el.outerHeight()
+ windowTop = $(window).scrollTop()
+ windowBottom = windowTop + $(window).height()
+ if viewTop < windowTop
+ $(window).scrollTop viewTop - TOP_OFFSET
+ if viewBottom > windowBottom
+ $(window).scrollTop $(window).scrollTop() - windowBottom + viewBottom + BOTTOM_OFFSET
+
+
<div class="navigator-facets-list-item-options">
{{#each values}}
{{#if count}}
- <a class="navigator-facets-list-item-option" data-key="{{val}}" data-property="{{../property}}">
- <span class="navigator-facets-list-item-option-name">{{text}}</span>
- <span class="navigator-facets-list-item-option-stat">{{count}}</span>
+ <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 class="component-viewer-header"></div>
<div class="component-viewer-workspace"></div>
-<div class="component-viewer-source"></div>
\ No newline at end of file
+<div class="component-viewer-source code-source"></div>
--- /dev/null
+<div class="navigator-filters-list"></div>
+<button class="navigator-filter-submit">{{t 'search_verb'}}</button>
--- /dev/null
+<div class="line line-small">
+ {{severityIcon severity}}{{translate "severities" severity}}
+ {{statusIcon status}}{{translate "statuses" status}}
+ {{#if resolution}}({{translate "resolutions" resolution}}){{/if}}
+
+ <div class="line-right">
+ {{fUpdateAge}}
+ </div>
+</div>
+
+<div class="line line-nowrap" title="{{message}}">
+ {{message}}
+</div>
+
+<div class="line">
+ {{#unless singleProject}}
+ <div class="subtitle line-nowrap">{{default projectLongName projectName}}</div>
+ {{/unless}}
+ <div class="subtitle line-nowrap">{{componentLongName}}</div>
+</div>
--- /dev/null
+{{#unless maxResultsReached}}
+ <div class="navigator-actions-order">
+ {{#if sorting}}
+ {{t 'issues.ordered_by'}} <strong class="navigator-actions-ordered-by">{{sorting.sortText}}</strong> {{#if sorting.asc}}<i class="icon-sort-asc"></i>{{else}}<i class="icon-sort-desc"></i>{{/if}}
+ {{else}}
+ Order
+ {{/if}}
+ </div>
+ <ul class="navigator-actions-order-choices">
+ <li data-sort="UPDATE_DATE" data-asc="true">{{t 'issues.sort.update_date'}} <i class="icon-sort-asc"></i></li>
+ <li data-sort="UPDATE_DATE" data-asc="false">{{t 'issues.sort.update_date'}} <i class="icon-sort-desc"></i></li>
+ <li data-sort="SEVERITY" data-asc="true">{{t 'issues.sort.severity'}} <i class="icon-sort-asc"></i></li>
+ <li data-sort="SEVERITY" data-asc="false">{{t 'issues.sort.severity'}} <i class="icon-sort-desc"></i></li>
+ <li data-sort="STATUS" data-asc="true">{{t 'issues.sort.status'}} <i class="icon-sort-asc"></i></li>
+ <li data-sort="STATUS" data-asc="false">{{t 'issues.sort.status'}} <i class="icon-sort-desc"></i></li>
+ </ul>
+{{/unless}}
+<div class="navigator-actions-total">
+ {{t 'issues.found'}}: <strong>{{paging.fTotal}}</strong>
+ {{#notEq paging.fTotal 0}}
+ {{#if appState.canBulkChange}}
+ <a href="{{bulkChangeUrl}}?{{query}}"
+ class="navigator-actions-bulk icon-bulk-change" title="{{t 'bulk_change'}}"></a>
+ {{/if}}
+ {{/notEq}}
+</div>
--- /dev/null
+{{#if items}}
+ <ul class="navigator-filter-select-list">
+ {{#each items}}
+ <li>
+ <label data-id="{{id}}">{{{name}}}</label>
+ </li>
+ {{/each}}
+ </ul>
+{{/if}}
+<ul class="navigator-filter-select-list">
+ <li class="manage">
+ <label id="manage-favorites">{{t 'manage'}}</label>
+ </li>
+</ul>
--- /dev/null
+<h1 class="navigator-header-title">
+ {{#if name}}
+ {{name}}
+ <span class="navigator-header-title-note">
+ {{#unless shared}}
+ [{{t 'issue_filter.private'}}]
+ {{else}}
+ {{#eq user currentUser}}
+ [{{t 'issue_filter.shared_with_all_users'}}]
+ {{else}}
+ {{#if user}}
+ [{{t 'issue_filter.shared'}}]
+ {{/if}}
+ {{/eq}}
+ {{/unless}}
+ </span>
+ {{else}}
+ {{t 'issues'}}
+ {{/if}}
+</h1>
+
+ <div class="navigator-header-actions button-group">
+ <button id="issues-new-search">{{t 'issue_filter.new_search'}}</button>
+
+ {{#if appState.canManageFilters}}
+ {{#if canModify}}
+ {{#if canSave}}<button id="issues-filter-save">{{t 'save'}}</button>{{/if}}
+ {{/if}}
+ {{#unless id}}<button id="issues-filter-save-as">{{t 'save_as'}}</button>{{/unless}}
+ {{#if id}}<button id="issues-filter-copy">{{t 'copy'}}</button>{{/if}}
+ {{#if canModify}}
+ {{#if id}}<button id="issues-filter-edit">{{t 'edit'}}</button>{{/if}}
+ {{/if}}
+ {{/if}}
+ </div>
+
+{{#if description}}
+ <div class="navigator-header-description">{{description}}</div>
+{{/if}}
--- /dev/null
+<ol class="navigator-results-list"></ol>
+<div class="navigator-results-loader">
+ <i class="spinner"></i>
+</div>
--- /dev/null
+{{t 'issue_filter.no_issues'}}
--- /dev/null
+<a class="issues-facet-header js-issues-facet-toggle">
+ <i class="icon-checkbox {{#if enabled}}icon-checkbox-checked{{/if}}"></i>
+ {{t 'issues.facet' property}}
+</a>
--- /dev/null
+{{> '_issues-facet-header'}}
+
+<div class="issues-facet-list">
+ {{#each values}}
+ {{#eq val ''}}
+ {{! unassigned }}
+ <a class="facet issues-facet js-issues-facet" data-unassigned>
+ <span class="facet-name">Unassigned</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{else}}
+ <a class="facet issues-facet js-issues-facet" data-value="{{val}}">
+ <span class="facet-name">{{label}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/eq}}
+ {{/each}}
+</div>
--- /dev/null
+{{> '_issues-facet-header'}}
+
+<div class="issues-facet-list">
+ {{#each values}}
+ <a class="facet issues-facet js-issues-facet" data-value="{{val}}">
+ <span class="facet-name">{{default label val}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/each}}
+</div>
--- /dev/null
+{{> '_issues-facet-header'}}
+
+<div class="issues-facet-container justify">
+ <input type="text" class="issues-facet-input" name="createdAfter" placeholder="From">
+ to
+ <input type="text" class="issues-facet-input" name="createdBefore" placeholder="To">
+</div>
+
+<input type="hidden" name="createdAt">
--- /dev/null
+{{> '_issues-facet-header'}}
+
+<div class="issues-facet-list">
+ {{#each values}}
+ {{#eq val ''}}
+ {{! unresolved }}
+ <a class="facet issues-facet issues-facet-half js-issues-facet" data-unresolved>
+ <span class="facet-name">Unresolved</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{else}}
+ <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}">
+ <span class="facet-name">{{t 'issue.resolution' val}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/eq}}
+ {{/each}}
+</div>
--- /dev/null
+{{> '_issues-facet-header'}}
+
+<div class="issues-facet-list">
+ {{#each values}}
+ <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}">
+ <span class="facet-name">{{severityIcon val}} {{t 'severity' val}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/each}}
+</div>
--- /dev/null
+{{> '_issues-facet-header'}}
+
+<div class="issues-facet-list">
+ {{#each values}}
+ <a class="facet issues-facet issues-facet-half js-issues-facet" data-value="{{val}}">
+ <span class="facet-name">{{statusIcon val}} {{t 'issue.status' val}}</span>
+ <span class="facet-stat">{{count}}</span>
+ </a>
+ {{/each}}
+</div>
+++ /dev/null
-<div class="navigator-filters-list"></div>
-<button class="navigator-filter-submit">{{t 'search_verb'}}</button>
+++ /dev/null
-<div class="line line-small">
- {{severityIcon severity}}{{translate "severities" severity}}
- {{statusIcon status}}{{translate "statuses" status}}
- {{#if resolution}}({{translate "resolutions" resolution}}){{/if}}
-
- <div class="line-right">
- {{fUpdateAge}}
- </div>
-</div>
-
-<div class="line line-nowrap" title="{{message}}">
- {{message}}
-</div>
-
-<div class="line">
- {{#unless singleProject}}
- <div class="subtitle line-nowrap">{{default projectLongName projectName}}</div>
- {{/unless}}
- <div class="subtitle line-nowrap">{{componentLongName}}</div>
-</div>
+++ /dev/null
-{{#unless maxResultsReached}}
- <div class="navigator-actions-order">
- {{#if sorting}}
- {{t 'issues.ordered_by'}} <strong class="navigator-actions-ordered-by">{{sorting.sortText}}</strong> {{#if sorting.asc}}<i class="icon-sort-asc"></i>{{else}}<i class="icon-sort-desc"></i>{{/if}}
- {{else}}
- Order
- {{/if}}
- </div>
- <ul class="navigator-actions-order-choices">
- <li data-sort="UPDATE_DATE" data-asc="true">{{t 'issues.sort.update_date'}} <i class="icon-sort-asc"></i></li>
- <li data-sort="UPDATE_DATE" data-asc="false">{{t 'issues.sort.update_date'}} <i class="icon-sort-desc"></i></li>
- <li data-sort="SEVERITY" data-asc="true">{{t 'issues.sort.severity'}} <i class="icon-sort-asc"></i></li>
- <li data-sort="SEVERITY" data-asc="false">{{t 'issues.sort.severity'}} <i class="icon-sort-desc"></i></li>
- <li data-sort="STATUS" data-asc="true">{{t 'issues.sort.status'}} <i class="icon-sort-asc"></i></li>
- <li data-sort="STATUS" data-asc="false">{{t 'issues.sort.status'}} <i class="icon-sort-desc"></i></li>
- </ul>
-{{/unless}}
-<div class="navigator-actions-total">
- {{t 'issues.found'}}: <strong>{{paging.fTotal}}</strong>
- {{#notEq paging.fTotal 0}}
- {{#if appState.canBulkChange}}
- <a href="{{bulkChangeUrl}}?{{query}}"
- class="navigator-actions-bulk icon-bulk-change" title="{{t 'bulk_change'}}"></a>
- {{/if}}
- {{/notEq}}
-</div>
--- /dev/null
+<div class="issues-workspace-component-viewer-code code-source">
+ {{#if hasSourceBefore}}
+ <i class="spinner js-component-viewer-source-before"></i>
+ {{/if}}
+
+ <table class="code">
+ {{#each source}}
+ <tr class="row" data-line-number="{{lineNumber}}">
+ <td class="stat ">{{lineNumber}}</td>
+ <td class="line"><pre>{{{code}}}</pre></td>
+ </tr>
+ {{/each}}
+ </table>
+
+ {{#if hasSourceAfter}}
+ <i class="spinner js-component-viewer-source-after"></i>
+ {{/if}}
+</div>
+++ /dev/null
-{{#if items}}
- <ul class="navigator-filter-select-list">
- {{#each items}}
- <li>
- <label data-id="{{id}}">{{{name}}}</label>
- </li>
- {{/each}}
- </ul>
-{{/if}}
-<ul class="navigator-filter-select-list">
- <li class="manage">
- <label id="manage-favorites">{{t 'manage'}}</label>
- </li>
-</ul>
--- /dev/null
+<div class="issues-filters-list">
+ {{#each items}}
+ <a class="issues-filters-button issues-filters-filter js-issues-filter" data-id="{{id}}">{{name}}</a>
+ <br>
+ {{/each}}
+</div>
+
+<div class="issues-filters-header">
+ {{#notEmpty items}}
+ <a class="issues-filters-button issues-filters-header-filters js-issues-toggle-filters">
+ {{default filter.name "Saved Filters"}}
+ </a>
+ {{/notEmpty}}
+
+ <span class="issues-filters-header-actions">
+ <a class="issues-filters-button js-issues-new-search">New Search</a>
+
+ {{#if state.canManageFilters}}
+ {{#if filter.canModify}}
+ {{#if state.changed}}
+ <a class="issues-filters-button js-issues-save">{{t 'save'}}</a>
+ {{/if}}
+ {{/if}}
+
+ {{#unless filter.id}}<a class="issues-filters-button js-issues-save-as">{{t 'save_as'}}</a>{{/unless}}
+
+ {{#if filter.id}}<a class="issues-filters-button js-issues-copy">{{t 'copy'}}</a>{{/if}}
+
+ {{#if filter.canModify}}
+ {{#if filter.id}}<a class="issues-filters-button js-issues-edit">{{t 'edit'}}</a>{{/if}}
+ {{/if}}
+ {{/if}}
+ </span>
+</div>
+++ /dev/null
-<h1 class="navigator-header-title">
- {{#if name}}
- {{name}}
- <span class="navigator-header-title-note">
- {{#unless shared}}
- [{{t 'issue_filter.private'}}]
- {{else}}
- {{#eq user currentUser}}
- [{{t 'issue_filter.shared_with_all_users'}}]
- {{else}}
- {{#if user}}
- [{{t 'issue_filter.shared'}}]
- {{/if}}
- {{/eq}}
- {{/unless}}
- </span>
- {{else}}
- {{t 'issues'}}
- {{/if}}
-</h1>
-
- <div class="navigator-header-actions button-group">
- <button id="issues-new-search">{{t 'issue_filter.new_search'}}</button>
-
- {{#if appState.canManageFilters}}
- {{#if canModify}}
- {{#if canSave}}<button id="issues-filter-save">{{t 'save'}}</button>{{/if}}
- {{/if}}
- {{#unless id}}<button id="issues-filter-save-as">{{t 'save_as'}}</button>{{/unless}}
- {{#if id}}<button id="issues-filter-copy">{{t 'copy'}}</button>{{/if}}
- {{#if canModify}}
- {{#if id}}<button id="issues-filter-edit">{{t 'edit'}}</button>{{/if}}
- {{/if}}
- {{/if}}
- </div>
-
-{{#if description}}
- <div class="navigator-header-description">{{description}}</div>
-{{/if}}
--- /dev/null
+<div class="code-issue code-issue-modern code-issue-collapsed" data-issue-key="{{key}}" data-issue-component="{{component}}" data-issue-rule="{{rule}}">
+ <div class="code-issue-name code-issue-toggle">
+ <div class="code-issue-name-rule">
+ {{severityIcon severity}} <span class="rulename">{{message}}</span>
+ </div>
+
+ <div class="code-issue-permalink">
+ <a target="_blank" href="{{permalink}}">
+ <i class="icon-link"></i>
+ </a>
+ </div>
+ </div>
+
+
+ <ul class="code-issue-actions code-issue-list">
+ {{#inArray actions "comment"}}
+ <li>
+ <a id="issue-comment" class="link-action">{{t 'issue.comment.formlink' }}</a>
+ </li>
+ {{/inArray}}
+
+
+ <li>
+ {{statusIcon status}}{{t 'issue.status' status}}
+ {{#if resolution}}({{t 'issue.resolution' resolution}}){{/if}}
+
+ {{#ifNotEmpty transitions}}
+ {{#each transitions}}
+ <a class="link-action issue-transition spacer-left" data-transition="{{this}}">{{t 'issue.transition' this}}</a>
+ {{/each}}
+ {{/ifNotEmpty}}
+ </li>
+
+
+ {{#inArray actions "assign"}}
+ <li>
+ {{#if assigneeName}}
+ <a id="issue-assign" class="link-action">{{t 'assigned_to'}}</a> {{assigneeName}}</li>
+ {{else}}
+ <a id="issue-assign" class="link-action">{{t 'issue.assign.formlink' }}</a>
+ {{#inArray actions "assign_to_me"}}
+ [<a id="issue-assign-to-me" class="link-action">{{t 'issue.assign.to_me' }}</a>]
+ {{/inArray}}
+ {{/if}}
+ </li>
+ {{else}}
+ {{#if assigneeName}}
+ <li>{{t 'assigned_to'}} <strong>{{assigneeName}}</strong></li>
+ {{/if}}
+ {{/inArray}}
+
+
+ {{#inArray actions "plan"}}
+ <li>
+ {{#if actionPlanName}}
+ <a id="issue-plan" class="link-action">{{t 'issue.planned_for'}}</a> {{actionPlanName}}
+ {{else}}
+ <a id="issue-plan" class="link-action">{{t 'issue.do_plan'}}</a>
+ {{/if}}
+ </li>
+ {{else}}
+ {{#if actionPlanName}}
+ <li>{{t 'issue.planned_for'}} <strong>{{actionPlanName}}</strong></li>
+ {{/if}}
+ {{/inArray}}
+
+
+ {{#ifHasExtraActions actions}}
+ <li>
+ <div class="dropdown">
+ <a class="link-action link-more" onclick="showDropdownMenuOnElement($j(this).next('.dropdown-menu')); return false;">{{t 'more_actions'}}</a>
+ <ul style="display: none" class="dropdown-menu">
+ {{#inArray actions "set_severity"}}
+ <li>
+ <a id="issue-set-severity" class="link-action spacer-right">{{t "issue.set_severity"}}</a>
+ </li>
+ {{/inArray}}
+ {{#pluginActions actions}}
+ <li>
+ <a class="link-action spacer-right issue-action" data-action="{{this}}">{{t "issue.action" this "formlink"}}</a>
+ </li>
+ {{/pluginActions}}
+ </ul>
+ </div>
+ </li>
+ {{else}}
+ {{#inArray actions "set_severity"}}
+ <li>
+ <a id="issue-set-severity" class="link-action">{{t "issue.set_severity"}}</a>
+ </li>
+ {{/inArray}}
+ {{/ifHasExtraActions}}
+
+ {{#if debt}}
+ <li>{{t 'issue.technical_debt_short'}}: {{debt}}</li>
+ {{/if}}
+
+ {{#if reporterName}}<li>{{t 'reporter'}}: {{reporterName}}</li>{{/if}}
+ {{#if author}}<li>{{t 'author'}}: {{author}}</li>{{/if}}
+ </ul>
+
+ <div class="code-issue-form" style="display: none;"></div>
+
+
+ <div class="code-issue-details">
+ <ul class="code-issue-tabs">
+ <li>
+ <a class="js-tab-link" href="#tab-issue-rule">{{t 'rule'}}</a>
+ </li>
+ <li>
+ <a class="js-tab-link" href="#tab-issue-changelog">{{t 'changelog'}}</a>
+ </li>
+ </ul>
+
+ <div id="tab-issue-rule" class="js-tab">
+ <div class="rule-desc"></div>
+ </div>
+
+ <div id="tab-issue-changelog" class="js-tab"></div>
+ </div>
+
+
+ <div class="code-issue-comments">
+ {{#each comments}}
+ <div class="code-issue-comment" data-comment-key="{{key}}">
+ <h4>
+ <i class="icon-comment"></i>
+ <b>{{userName}}</b>
+ ({{fromNow createdAt}})
+
+ {{#if updatable}}
+
+ <a class="link-action issue-comment-edit">{{t 'edit'}}</a>
+ <a class="link-action link-red spacer-right issue-comment-delete"
+ data-confirm-msg="{{t 'issue.comment.delete_confirm_message'}}">{{t 'delete'}}</a>
+ {{/if}}
+ </h4>
+ <div class="markdown">{{{show html htmlText}}}</div>
+ </div>
+ {{/each}}
+ </div>
+</div>
--- /dev/null
+<div class="issues-side">
+ <div class="issues-filters"></div>
+ <div class="issues-facets"></div>
+</div>
+
+<div class="issues-workspace">
+ <div class="issues-workspace-header issues-header"></div>
+ <div class="issues-workspace-list"></div>
+ <div class="issues-workspace-component-viewer"></div>
+</div>
--- /dev/null
+{{#if state.component}}
+ <span class="issues-header-item">
+ <a class="js-back">Return to List</a>
+ </span>
+
+ <span class="issues-header-item">
+ {{state.component.projectName}} {{state.component.name}}
+ </span>
+{{/if}}
+
+<span class="issues-header-item issues-header-nav">
+ <a class="icon-bulk-change js-issues-bulk-change"></a>
+</span>
+
+{{#if state.total}}
+ <span class="issues-header-item issues-header-nav">
+ <a class="js-issues-prev icon-prev"></a>
+ <span class="current">{{sum state.selectedIndex 1}} / {{state.total}}</span>
+ <a class="js-issues-next icon-next"></a>
+ </span>
+{{/if}}
--- /dev/null
+<div class="issue-box-component subtitle">
+ <a href="{{dashboardUrl project}}">{{projectLongName}}</a>
+
+ <a href="{{dashboardUrl component}}">{{componentLongName}}</a>
+</div>
+
+{{#if source}}
+ <div class="issue-box-snippet code-source js-issues-snippet">
+ <table class="code">
+ <tr class="row">
+ {{#if scmAuthor}}
+ <td class="stat scm">
+ <span class="scm-date">{{scmDate}}</span>
+ <span class="scm-author" title="{{scmAuthor}}">{{scmAuthor}}</span>
+ </td>
+ {{/if}}
+ <td class="stat lid">{{line}}</td>
+ <td class="line issue"><pre>{{{source}}}</pre></td>
+ </tr>
+ </table>
+ </div>
+{{/if}}
+
+<div class="issue-box-details"></div>
--- /dev/null
+<ul></ul>
+
+<div class="issues-workspace-list-more js-issues-more">
+ <i class="spinner"></i>
+</div>
+++ /dev/null
-<ol class="navigator-results-list"></ol>
-<div class="navigator-results-loader">
- <i class="spinner"></i>
-</div>
+++ /dev/null
-{{t 'issue_filter.no_issues'}}
});
Handlebars.registerHelper('dashboardUrl', function(componentKey, componentQualifier) {
- var url = baseUrl + '/dashboard/index/' + decodeURIComponent(componentKey);
+ var url = baseUrl + '/dashboard/index?id=' + encodeURIComponent(componentKey);
if (componentQualifier === 'FIL' || componentQualifier === 'CLA') {
- url += '?metric=sqale_index';
+ url += '&metric=sqale_index';
}
return url;
});
}
});
+ Handlebars.registerHelper('withLast', function(list, options) {
+ if (list && list.length > 0) {
+ return options.fn(list[list.length - 1]);
+ } else {
+ return '';
+ }
+ });
+
Handlebars.registerHelper('withoutFirst', function(list, options) {
if (list && list.length > 1) {
return list.slice(1).reduce(function(prev, current) {
--- /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', 'handlebars',
+ 'issues-old/extra',
+ 'navigator/filters/filter-bar',
+ 'navigator/filters/base-filters',
+ 'navigator/filters/checkbox-filters',
+ 'navigator/filters/choice-filters',
+ 'navigator/filters/ajax-select-filters',
+ 'navigator/filters/favorite-filters',
+ 'navigator/filters/range-filters',
+ 'navigator/filters/context-filters',
+ 'navigator/filters/read-only-filters',
+ 'navigator/filters/action-plan-filters',
+ 'navigator/filters/rule-filters',
+
+ 'common/handlebars-extensions'
+ ],
+ function (Backbone, Marionette, Handlebars, Extra, FilterBar, BaseFilters, CheckboxFilterView,
+ ChoiceFilters, AjaxSelectFilters, FavoriteFilters, RangeFilters, ContextFilterView,
+ ReadOnlyFilterView, ActionPlanFilterView, RuleFilterView) {
+ Handlebars.registerPartial('detailInnerTemplate', jQuery('#issue-detail-inner-template').html());
+
+ var NavigatorApp = new Marionette.Application();
+
+
+ NavigatorApp.addRegions({
+ headerRegion: '.navigator-header',
+ filtersRegion: '.navigator-filters',
+ resultsRegion: '.navigator-results',
+ actionsRegion: '.navigator-actions',
+ detailsRegion: '.navigator-details'
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ jQuery('html').addClass('navigator-page issues-page');
+
+ this.appState = new Extra.AppState();
+ window.SS.appState = this.appState;
+
+ this.state = new Backbone.Model({
+ query: ''
+ });
+
+ this.issues = new Extra.Issues();
+ this.issues.sorting = {
+ sort: 'UPDATE_DATE',
+ asc: false
+ };
+ this.issuesPage = 1;
+
+ this.filters = new BaseFilters.Filters();
+
+ this.favoriteFilter = new Extra.FavoriteFilter();
+ this.issuesHeaderView = new Extra.IssuesHeaderView({
+ app: this,
+ model: this.favoriteFilter
+ });
+ this.headerRegion.show(this.issuesHeaderView);
+
+ this.issuesView = new Extra.IssuesView({
+ app: this,
+ collection: this.issues
+ });
+ this.resultsRegion.show(this.issuesView);
+
+ this.issuesActionsView = new Extra.IssuesActionsView({
+ app: this,
+ collection: this.issues
+ });
+ this.actionsRegion.show(this.issuesActionsView);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.projectFilter = new BaseFilters.Filter({
+ name: window.SS.phrases.project,
+ property: 'componentRoots',
+ type: AjaxSelectFilters.ProjectFilterView,
+ enabled: true,
+ optional: false
+ });
+ this.filters.add(this.projectFilter);
+
+ this.assigneeChoices = {
+ '!assigned': window.SS.phrases.unassigned
+ };
+ this.reporterChoices = {};
+ if (window.SS.currentUser) {
+ this.assigneeChoices[window.SS.currentUser] = window.SS.currentUserName + ' (' + window.SS.currentUser + ')';
+ this.reporterChoices[window.SS.currentUser] = window.SS.currentUserName + ' (' + window.SS.currentUser + ')';
+ }
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.severity,
+ property: 'severities',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ 'BLOCKER': window.SS.phrases.severities.BLOCKER,
+ 'CRITICAL': window.SS.phrases.severities.CRITICAL,
+ 'MAJOR': window.SS.phrases.severities.MAJOR,
+ 'MINOR': window.SS.phrases.severities.MINOR,
+ 'INFO': window.SS.phrases.severities.INFO
+ },
+ choiceIcons: {
+ 'BLOCKER': 'severity-blocker',
+ 'CRITICAL': 'severity-critical',
+ 'MAJOR': 'severity-major',
+ 'MINOR': 'severity-minor',
+ 'INFO': 'severity-info'
+ }
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.status,
+ property: 'statuses',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ 'OPEN': window.SS.phrases.statuses.OPEN,
+ 'CONFIRMED': window.SS.phrases.statuses.CONFIRMED,
+ 'REOPENED': window.SS.phrases.statuses.REOPENED,
+ 'RESOLVED': window.SS.phrases.statuses.RESOLVED,
+ 'CLOSED': window.SS.phrases.statuses.CLOSED
+ },
+ choiceIcons: {
+ 'OPEN': 'status-open',
+ 'CONFIRMED': 'status-confirmed',
+ 'REOPENED': 'status-reopened',
+ 'RESOLVED': 'status-resolved',
+ 'CLOSED': 'status-closed'
+ }
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.assignee,
+ property: 'assignees',
+ type: AjaxSelectFilters.AssigneeFilterView,
+ enabled: true,
+ optional: false,
+ choices: this.assigneeChoices
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.resolution,
+ property: 'resolutions',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: true,
+ optional: false,
+ choices: {
+ '!resolved=true': window.SS.phrases.resolutions.RESOLVED,
+ '!resolved=false': window.SS.phrases.resolutions.UNRESOLVED,
+ 'FALSE-POSITIVE': window.SS.phrases.resolutions['FALSE-POSITIVE'],
+ 'FIXED': window.SS.phrases.resolutions.FIXED,
+ 'REMOVED': window.SS.phrases.resolutions.REMOVED
+ }
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.actionPlan,
+ property: 'actionPlans',
+ type: ActionPlanFilterView,
+ enabled: false,
+ optional: true,
+ projectFilter: this.projectFilter,
+ choices: {
+ '!planned': window.SS.phrases.unplanned
+ }
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.created,
+ propertyFrom: 'createdAfter',
+ propertyTo: 'createdBefore',
+ type: RangeFilters.DateRangeFilterView,
+ enabled: false,
+ optional: true
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.createdAt,
+ property: 'createdAt',
+ type: ReadOnlyFilterView,
+ enabled: false,
+ optional: true,
+ format: function(value) { return moment(value).format('YYYY-MM-DD HH:mm'); }
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.language,
+ property: 'languages',
+ type: ChoiceFilters.ChoiceFilterView,
+ enabled: false,
+ optional: true,
+ choices: window.SS.languages
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.reporter,
+ property: 'reporters',
+ type: AjaxSelectFilters.ReporterFilterView,
+ enabled: false,
+ optional: true,
+ choices: this.reporterChoices
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filters.add([
+ new BaseFilters.Filter({
+ name: window.SS.phrases.rule,
+ property: 'rules',
+ type: RuleFilterView,
+ enabled: false,
+ optional: true
+ })
+ ]);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.filterBarView = new Extra.IssuesFilterBarView({
+ app: this,
+ collection: this.filters,
+ extra: {
+ sort: '',
+ asc: false
+ }
+ });
+
+ this.filtersRegion.show(this.filterBarView);
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ var app = this;
+
+ jQuery.when(this.appState.fetch()).done(function () {
+
+ if (app.appState.get('favorites')) {
+ app.filters.unshift(
+ new BaseFilters.Filter({
+ type: Extra.IssuesFavoriteFilterView,
+ enabled: true,
+ optional: false,
+ choices: app.appState.get('favorites'),
+ manageUrl: '/issues/manage'
+ })
+ );
+ }
+
+ app.router = new Extra.IssuesRouter({
+ app: app
+ });
+ Backbone.history.start();
+
+ app.favoriteFilter.on('change:query', function (model, query) {
+ app.router.navigate(query, { trigger: true, replace: true });
+ });
+ });
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ var app = this;
+
+ window.onBulkIssues = function () {
+ app.fetchFirstPage();
+ jQuery('#modal').dialog('close');
+ };
+
+ window.onSaveAs = window.onCopy = window.onEdit = function (id) {
+ jQuery('#modal').dialog('close');
+ app.appState.fetch();
+
+ var filter = new Extra.FavoriteFilter({ id: id });
+ filter.fetch({
+ success: function () {
+ app.state.set('search', false);
+ app.favoriteFilter.set(filter.toJSON());
+ app.fetchFirstPage();
+ }
+ });
+ };
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ this.onResize = function() {
+ var footerEl = jQuery('#footer'),
+ footerHeight = footerEl.outerHeight(true);
+
+ var resultsEl = jQuery('.navigator-results'),
+ resultsHeight = jQuery(window).height() - resultsEl.offset().top -
+ parseInt(resultsEl.css('margin-bottom'), 10) - footerHeight;
+ resultsEl.height(resultsHeight);
+
+ var detailsEl = jQuery('.navigator-details'),
+ detailsWidth = jQuery(window).width() - detailsEl.offset().left -
+ parseInt(detailsEl.css('margin-right'), 10) - 20,
+ detailsHeight = jQuery(window).height() - detailsEl.offset().top -
+ parseInt(detailsEl.css('margin-bottom'), 10) - footerHeight;
+ detailsEl.width(detailsWidth).height(detailsHeight);
+
+ var resultsLoadingEl = jQuery('.navigator-results-loader');
+ resultsLoadingEl
+ .css('top', resultsEl.offset().top)
+ .css('left', resultsEl.offset().left)
+ .width(resultsEl.width() + 10)
+ .height(resultsEl.height() + 10);
+ };
+ jQuery(window).on('resize', this.onResize);
+ this.onResize();
+ });
+
+
+ NavigatorApp.addInitializer(function () {
+ var that = this;
+ jQuery('body')
+ .on('mousemove', function (e) {
+ that.processResize(e);
+ })
+ .on('mouseup', function () {
+ that.stopResize();
+ });
+ jQuery('.navigator-resizer').on('mousedown', function (e) {
+ that.startResize(e);
+ });
+
+ var resultsWidth = localStorage.getItem('issuesResultsWidth');
+ if (resultsWidth) {
+ jQuery('.navigator-results').width(+resultsWidth);
+ jQuery('.navigator-side').width(+resultsWidth + 20);
+ this.onResize();
+ }
+ });
+
+
+ NavigatorApp.startResize = function (e) {
+ this.isResize = true;
+ this.originalWidth = jQuery('.navigator-results').width();
+ this.x = e.clientX;
+ jQuery('html').attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false);
+ };
+
+
+ NavigatorApp.processResize = function (e) {
+ if (this.isResize) {
+ var delta = e.clientX - this.x;
+ jQuery('.navigator-results').width(this.originalWidth + delta);
+ jQuery('.navigator-side').width(this.originalWidth + 20 + delta);
+ localStorage.setItem('issuesResultsWidth', jQuery('.navigator-results').width());
+ this.onResize();
+ }
+ };
+
+
+ NavigatorApp.stopResize = function() {
+ if (this.isResize) {
+ jQuery('html').attr('unselectable', 'off').css('user-select', 'text').off('selectstart');
+ }
+ this.isResize = false;
+ };
+
+
+ NavigatorApp.getQuery = function (withoutId) {
+ if (this.filterBarView) {
+ var query = this.filterBarView.getQuery();
+ if (!withoutId && this.favoriteFilter.id) {
+ query['id'] = this.favoriteFilter.id;
+ }
+ return query;
+ } else {
+ return {};
+ }
+ };
+
+
+ NavigatorApp.storeQuery = function (query, sorting) {
+ if (sorting) {
+ _.extend(query, {
+ sort: sorting.sort,
+ asc: '' + sorting.asc
+ });
+ }
+
+ var queryString = _.map(query,function (v, k) {
+ return [k, encodeURIComponent(v)].join('=');
+ }).join('|');
+ this.router.navigate(queryString, { replace: true });
+ };
+
+
+ NavigatorApp.restoreSorting = function (query) {
+ var sort = _.findWhere(query, { key: 'sort' }),
+ asc = _.findWhere(query, { key: 'asc' });
+
+ if (sort && asc) {
+ this.issues.sorting = {
+ sort: sort.value,
+ sortText: jQuery('[data-sort=' + sort.value + ']:first').text(),
+ asc: asc.value === 'true'
+ };
+ }
+ };
+
+
+ NavigatorApp.fetchIssues = function (firstPage) {
+ var query = this.getQuery(),
+ fetchQuery = _.extend({
+ pageIndex: this.issuesPage
+ }, query);
+
+ // SONAR-5086
+ if (fetchQuery['actionPlans'] && fetchQuery['componentRoots']) {
+ delete fetchQuery['componentRoots'];
+ }
+
+ if (this.issues.sorting) {
+ _.extend(fetchQuery, {
+ sort: this.issues.sorting.sort,
+ asc: this.issues.sorting.asc
+ });
+ }
+
+ _.extend(fetchQuery, {
+ hideRules: true
+ });
+
+ if (this.favoriteFilter.id) {
+ query['id'] = this.favoriteFilter.id;
+ fetchQuery['id'] = this.favoriteFilter.id;
+ }
+
+ this.storeQuery(query, this.issues.sorting);
+
+ var that = this;
+ jQuery('.navigator-results').addClass('fetching');
+ if (firstPage) {
+ this.issues.fetch({
+ data: fetchQuery,
+ success: function () {
+ jQuery('.navigator-results').removeClass('fetching');
+ that.issuesView.selectFirst();
+ }
+ });
+ this.detailsRegion.reset();
+ } else {
+ this.issues.fetch({
+ data: fetchQuery,
+ remove: false,
+ success: function () {
+ jQuery('.navigator-results').removeClass('fetching');
+ }
+ });
+ }
+ };
+
+
+ NavigatorApp.fetchFirstPage = function () {
+ this.issuesPage = 1;
+ this.fetchIssues(true);
+ };
+
+
+ NavigatorApp.fetchNextPage = function () {
+ if (this.issuesPage < this.issues.paging.pages) {
+ this.issuesPage++;
+ this.fetchIssues(false);
+ }
+ };
+
+ window.requestMessages().done(function () {
+ NavigatorApp.start();
+ });
+
+ });
--- /dev/null
+define(
+ [
+ 'backbone',
+ 'backbone.marionette',
+ 'navigator/filters/filter-bar',
+ 'navigator/filters/base-filters',
+ 'navigator/filters/favorite-filters',
+ 'navigator/filters/read-only-filters',
+ 'component-viewer/main',
+ 'templates/issues-old'
+ ],
+ function (Backbone, Marionette, FilterBarView, BaseFilters, FavoriteFiltersModule, ReadOnlyFilterView,
+ ComponentViewer, Templates) {
+
+ var AppState = Backbone.Model.extend({
+
+ defaults: {
+ canManageFilters: false,
+ canBulkChange: false
+ },
+
+
+ url: function () {
+ return baseUrl + '/api/issue_filters/app';
+ }
+
+ });
+
+
+ var Issue = Backbone.Model.extend({
+
+ url: function () {
+ return baseUrl + '/api/issues/show?key=' + this.get('key');
+ },
+
+
+ parse: function (r) {
+ return r.issue ? r.issue : r;
+ }
+
+ });
+
+
+ var Issues = Backbone.Collection.extend({
+ model: Issue,
+
+
+ url: function () {
+ return baseUrl + '/api/issues/search';
+ },
+
+
+ parse: function (r) {
+
+ function find(source, key, keyField) {
+ var searchDict = {};
+ searchDict[keyField || 'key'] = key;
+ return _.findWhere(source, searchDict) || key;
+ }
+
+ this.paging = r.paging;
+ this.maxResultsReached = r.maxResultsReached;
+
+ return r.issues.map(function (issue) {
+ var component = find(r.components, issue.component),
+ project = find(r.projects, issue.project),
+ rule = find(r.rules, issue.rule);
+
+ if (component) {
+ _.extend(issue, {
+ componentLongName: component.longName,
+ componentQualifier: component.qualifier
+ });
+ }
+
+ if (project) {
+ _.extend(issue, {
+ projectLongName: project.longName
+ });
+ }
+
+ if (rule) {
+ _.extend(issue, {
+ ruleName: rule.name
+ });
+ }
+
+ return issue;
+ });
+
+ }
+ });
+
+
+ var FavoriteFilter = Backbone.Model.extend({
+
+ url: function () {
+ return baseUrl + '/api/issue_filters/show/' + this.get('id');
+ },
+
+
+ parse: function (r) {
+ return r.filter ? r.filter : r;
+ }
+ });
+
+
+ var FavoriteFilters = Backbone.Collection.extend({
+ model: FavoriteFilter,
+
+
+ url: function () {
+ return baseUrl + '/api/issue_filters/favorites';
+ },
+
+
+ parse: function (r) {
+ return r.favoriteFilters;
+ }
+ });
+
+
+ var IssueView = Marionette.ItemView.extend({
+ template: Templates['issue-detail'],
+ tagName: 'li',
+
+
+ ui: {
+ component: '.component'
+ },
+
+
+ events: {
+ 'click': 'showDetails'
+ },
+
+
+ modelEvents: {
+ 'change': 'render'
+ },
+
+
+ showDetails: function () {
+ key.setScope('list');
+ this.options.issuesView.selected = this.$el.parent().children().index(this.$el);
+
+ this.options.issuesView.selectIssue(this.$el, false);
+
+ var that = this,
+ app = this.options.app,
+ settings = localStorage.getItem('componentViewerSettings'),
+ navigatorDetails = jQuery('.navigator-details'),
+ componentViewer = new ComponentViewer({
+ settings: settings,
+ shouldStoreSettings: true,
+ elementToFit: navigatorDetails,
+ component: {
+ project: this.model.get('project'),
+ projectLongName: this.model.get('projectLongName')
+ }
+ }),
+ showCallback = function () {
+ navigatorDetails.removeClass('navigator-fetching');
+ app.detailsRegion.show(componentViewer);
+ componentViewer.settings.set('issues', false);
+ componentViewer.open(that.model.get('component'));
+ componentViewer.on('loaded', function() {
+ componentViewer.off('loaded');
+ componentViewer.showIssues(false, that.model.toJSON());
+ });
+ };
+
+ navigatorDetails.empty().addClass('navigator-fetching');
+ var issueKey = this.model.get('key');
+ this.model.clear({ silent: true });
+ this.model.set({ key: issueKey }, { silent: true });
+ jQuery.when(this.model.fetch()).done(showCallback);
+ },
+
+
+ serializeData: function () {
+ var projectFilter = this.options.app.filters.findWhere({ property: 'componentRoots' }),
+ singleProject = _.isArray(projectFilter.get('value')) && projectFilter.get('value').length === 1;
+
+ return _.extend({
+ singleProject: singleProject
+ }, this.model.toJSON());
+ }
+ });
+
+
+ var NoIssuesView = Marionette.ItemView.extend({
+ tagName: 'li',
+ className: 'navigator-results-no-results',
+ template: Templates['no-issues']
+ });
+
+
+ var IssuesView = Marionette.CompositeView.extend({
+ template: Templates['issues'],
+ itemViewContainer: '.navigator-results-list',
+ itemView: IssueView,
+ emptyView: NoIssuesView,
+
+
+ initialize: function() {
+ var openIssue = function(el) {
+ el.click();
+ };
+ this.openIssue = _.debounce(openIssue, 300);
+ },
+
+
+ itemViewOptions: function () {
+ return {
+ issuesView: this,
+ app: this.options.app
+ };
+ },
+
+
+ selectIssue: function(el, open) {
+ this.$('.active').removeClass('active');
+ el.addClass('active');
+ if (open) {
+ this.openIssue(el);
+ }
+ },
+
+
+ selectFirst: function() {
+ this.selected = -1;
+ this.selectNext();
+ },
+
+
+ selectNext: function() {
+ if (this.selected < this.collection.length - 1) {
+ this.selected++;
+ var child = this.$(this.itemViewContainer).children().eq(this.selected),
+ container = jQuery('.navigator-results'),
+ containerHeight = container.height(),
+ bottom = child.position().top + child.outerHeight();
+ if (bottom > containerHeight) {
+ container.scrollTop(container.scrollTop() - containerHeight + bottom);
+ }
+ this.selectIssue(child, true);
+ }
+ },
+
+
+ selectPrev: function() {
+ if (this.selected > 0) {
+ this.selected--;
+ var child = this.$(this.itemViewContainer).children().eq(this.selected),
+ container = jQuery('.navigator-results'),
+ top = child.position().top;
+ if (top < 0) {
+ container.scrollTop(container.scrollTop() + top);
+ }
+ this.selectIssue(child, true);
+ }
+ },
+
+
+ onRender: function () {
+ var that = this,
+ $scrollEl = jQuery('.navigator-results'),
+ scrollEl = $scrollEl.get(0),
+ onScroll = function () {
+ if (scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight) {
+ that.options.app.fetchNextPage();
+ }
+ },
+ throttledScroll = _.throttle(onScroll, 300);
+ $scrollEl.off('scroll').on('scroll', throttledScroll);
+ this.bindShortcuts();
+ },
+
+
+ onAfterItemAdded: function () {
+ var showLimitNotes = this.collection.maxResultsReached != null && this.collection.maxResultsReached;
+ jQuery('.navigator').toggleClass('navigator-with-notes', showLimitNotes);
+ jQuery('.navigator-notes').toggle(showLimitNotes);
+ },
+
+
+ close: function () {
+ var scrollEl = jQuery('.navigator-results');
+ scrollEl.off('scroll');
+ Marionette.CollectionView.prototype.close.call(this);
+ },
+
+
+ bindShortcuts: function () {
+ var that = this;
+ key('up', 'list', function() {
+ that.selectPrev();
+ });
+ key('down', 'list', function() {
+ that.selectNext();
+ });
+ }
+
+ });
+
+
+ var IssuesActionsView = Marionette.ItemView.extend({
+ template: Templates['issues-actions'],
+
+
+ collectionEvents: {
+ 'sync': 'render'
+ },
+
+
+ events: {
+ 'click .navigator-actions-order': 'toggleOrderChoices',
+ 'click .navigator-actions-order-choices': 'sort',
+ 'click .navigator-actions-bulk': 'bulkChange'
+ },
+
+
+ ui: {
+ orderChoices: '.navigator-actions-order-choices'
+ },
+
+
+ onRender: function () {
+ if (!this.collection.sorting.sortText) {
+ this.collection.sorting.sortText = this.$('[data-sort=' + this.collection.sorting.sort + ']:first').text();
+ this.$('.navigator-actions-ordered-by').text(this.collection.sorting.sortText);
+ }
+ },
+
+
+ toggleOrderChoices: function (e) {
+ e.stopPropagation();
+ this.ui.orderChoices.toggleClass('open');
+ if (this.ui.orderChoices.is('.open')) {
+ var that = this;
+ jQuery('body').on('click.issues_actions', function () {
+ that.ui.orderChoices.removeClass('open');
+ });
+ }
+ },
+
+
+ sort: function (e) {
+ e.stopPropagation();
+ this.ui.orderChoices.removeClass('open');
+ jQuery('body').off('click.issues_actions');
+ var el = jQuery(e.target),
+ sort = el.data('sort'),
+ asc = el.data('asc');
+
+ if (sort != null && asc != null) {
+ this.collection.sorting = {
+ sort: sort,
+ sortText: el.text(),
+ asc: asc
+ };
+ this.options.app.fetchFirstPage();
+ }
+ },
+
+
+ bulkChange: function(e) {
+ e.preventDefault();
+ openModalWindow(jQuery(e.currentTarget).prop('href'), {});
+ },
+
+
+ serializeData: function () {
+ var data = Marionette.ItemView.prototype.serializeData.apply(this, arguments),
+ bulkChangeData = this.options.app.getQuery(true),
+ bulkChangeQuery = _.map(bulkChangeData,function (v, k) {
+ return [k, encodeURIComponent(v)].join('=');
+ }).join('&');
+ return _.extend(data || {}, {
+ paging: this.collection.paging,
+ sorting: this.collection.sorting,
+ maxResultsReached: this.collection.maxResultsReached,
+ appState: window.SS.appState.toJSON(),
+ bulkChangeUrl: baseUrl + '/issues/bulk_change_form',
+ query: bulkChangeQuery
+ });
+ }
+ });
+
+
+
+ var IssuesDetailsFavoriteFilterView = FavoriteFiltersModule.DetailsFavoriteFilterView.extend({
+ template: Templates['issues-details-favorite-filter'],
+
+
+ applyFavorite: function (e) {
+ var id = $j(e.target).data('id'),
+ filter = new FavoriteFilter({ id: id }),
+ app = this.options.filterView.options.app;
+
+ filter.fetch({
+ success: function () {
+ app.state.set('search', false);
+ app.favoriteFilter.clear({ silent: true });
+ app.favoriteFilter.set(filter.toJSON());
+ }
+ });
+
+ this.options.filterView.hideDetails();
+ },
+
+
+ serializeData: function () {
+ return _.extend({}, this.model.toJSON(), {
+ items: _.sortBy(this.model.get('choices'), function(item) {
+ return item.name.toLowerCase();
+ })
+ });
+ }
+ });
+
+
+
+ var IssuesFavoriteFilterView = FavoriteFiltersModule.FavoriteFilterView.extend({
+
+ initialize: function () {
+ BaseFilters.BaseFilterView.prototype.initialize.call(this, {
+ detailsView: IssuesDetailsFavoriteFilterView
+ });
+
+ this.listenTo(window.SS.appState, 'change:favorites', this.updateFavorites);
+ },
+
+
+ updateFavorites: function () {
+ this.model.set('choices', window.SS.appState.get('favorites'));
+ this.render();
+ }
+ });
+
+
+
+ var IssuesFilterBarView = FilterBarView.extend({
+ template: Templates['filter-bar'],
+
+ collectionEvents: {
+ 'change:enabled': 'changeEnabled'
+ },
+
+
+ events: {
+ 'click .navigator-filter-submit': 'search'
+ },
+
+
+ getQuery: function () {
+ var query = {};
+ this.collection.each(function (filter) {
+ _.extend(query, filter.view.formatValue());
+ });
+ return query;
+ },
+
+
+ onAfterItemAdded: function (itemView) {
+ if (itemView.model.get('type') === FavoriteFiltersModule.FavoriteFilterView ||
+ itemView.model.get('type') === IssuesFavoriteFilterView) {
+ jQuery('.navigator-header').addClass('navigator-header-favorite');
+ }
+ },
+
+
+ addMoreCriteriaFilter: function() {
+ var readOnlyFilters = this.collection.where({ type: ReadOnlyFilterView }),
+ disabledFilters = _.difference(this.collection.where({ enabled: false }), readOnlyFilters);
+ this.moreCriteriaFilter = new BaseFilters.Filter({
+ type: require('navigator/filters/more-criteria-filters').MoreCriteriaFilterView,
+ enabled: true,
+ optional: false,
+ filters: disabledFilters
+ });
+ this.collection.add(this.moreCriteriaFilter);
+ },
+
+
+ changeEnabled: function () {
+ var disabledFilters = _.reject(this.collection.where({ enabled: false }), function (filter) {
+ return filter.get('type') ===
+ require('navigator/filters/more-criteria-filters').MoreCriteriaFilterView ||
+ filter.get('type') === ReadOnlyFilterView;
+ });
+
+ if (disabledFilters.length === 0) {
+ this.moreCriteriaFilter.set({ enabled: false }, { silent: true });
+ } else {
+ this.moreCriteriaFilter.set({ enabled: true }, { silent: true });
+ }
+ this.moreCriteriaFilter.set({ filters: disabledFilters }, { silent: true });
+ this.moreCriteriaFilter.trigger('change:filters');
+ },
+
+
+ search: function () {
+ this.$('.navigator-filter-submit').blur();
+ this.options.app.state.set({
+ query: this.options.app.getQuery(),
+ search: true
+ });
+ this.options.app.fetchFirstPage();
+ },
+
+
+ fetchNextPage: function () {
+ this.options.app.fetchNextPage();
+ }
+
+ });
+
+
+ var IssuesHeaderView = Marionette.ItemView.extend({
+ template: Templates['issues-header'],
+
+
+ modelEvents: {
+ 'change': 'render'
+ },
+
+
+ events: {
+ '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'
+ },
+
+
+ initialize: function (options) {
+ Marionette.ItemView.prototype.initialize.apply(this, arguments);
+ this.listenTo(options.app.state, 'change', this.render);
+ },
+
+
+ newSearch: function () {
+ this.model.clear();
+ this.options.app.router.navigate('resolved=false', { trigger: true, replace: true });
+ },
+
+
+ saveAs: function () {
+ var url = baseUrl + '/issues/save_as_form?' + (Backbone.history.fragment || '').replace(/\|/g, '&');
+ openModalWindow(url, {});
+ },
+
+
+ save: function () {
+ var that = this;
+ url = baseUrl + '/issues/save/' + this.model.id + '?' + (Backbone.history.fragment || '').replace(/\|/g, '&');
+ jQuery.ajax({
+ type: 'POST',
+ url: url
+ }).done(function () {
+ that.options.app.state.set('search', false);
+ });
+ },
+
+
+ copy: function () {
+ var url = baseUrl + '/issues/copy_form/' + this.model.id;
+ openModalWindow(url, {});
+ },
+
+
+ edit: function () {
+ var url = baseUrl + '/issues/edit_form/' + this.model.id;
+ openModalWindow(url, {});
+ },
+
+
+ serializeData: function () {
+ return _.extend({
+ canSave: this.model.id && this.options.app.state.get('search'),
+ appState: window.SS.appState.toJSON(),
+ currentUser: window.SS.currentUser
+ }, this.model.toJSON());
+ }
+
+ });
+
+
+
+ var IssuesRouter = Backbone.Router.extend({
+
+ routes: {
+ '': 'emptyQuery',
+ ':query': 'index'
+ },
+
+
+ initialize: function (options) {
+ this.app = options.app;
+ },
+
+
+ parseQuery: function (query, separator) {
+ return (query || '').split(separator || '|').map(function (t) {
+ var tokens = t.split('=');
+ return {
+ key: tokens[0],
+ value: decodeURIComponent(tokens[1])
+ };
+ });
+ },
+
+
+ emptyQuery: function () {
+ this.navigate('resolved=false', { trigger: true, replace: true });
+ },
+
+
+ index: function (query) {
+ var params = this.parseQuery(query);
+
+ var idObj = _.findWhere(params, { key: 'id' });
+ if (idObj) {
+ var that = this,
+ f = this.app.favoriteFilter;
+ this.app.canSave = false;
+ f.set('id', idObj.value);
+ f.fetch({
+ success: function () {
+ var parsedFilter = that.parseQuery(f.get('query'));
+ params = _.extend({}, params);
+ params = _.extent(params, parsedFilter);
+ that.loadResults(params);
+ }
+ });
+ } else {
+ this.loadResults(params);
+ }
+ },
+
+
+ loadResults: function (params) {
+ this.app.filterBarView.restoreFromQuery(params);
+ this.app.restoreSorting(params);
+ this.app.fetchFirstPage();
+ }
+
+ });
+
+
+ /*
+ * Export public classes
+ */
+
+ return {
+ AppState: AppState,
+ Issue: Issue,
+ Issues: Issues,
+ FavoriteFilter: FavoriteFilter,
+ FavoriteFilters: FavoriteFilters,
+ IssueView: IssueView,
+ IssuesView: IssuesView,
+ IssuesActionsView: IssuesActionsView,
+ IssuesFilterBarView: IssuesFilterBarView,
+ IssuesHeaderView: IssuesHeaderView,
+ IssuesFavoriteFilterView: IssuesFavoriteFilterView,
+ IssuesRouter: IssuesRouter
+ };
+
+ });
+++ /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', 'handlebars',
- 'issues/extra',
- 'navigator/filters/filter-bar',
- 'navigator/filters/base-filters',
- 'navigator/filters/checkbox-filters',
- 'navigator/filters/choice-filters',
- 'navigator/filters/ajax-select-filters',
- 'navigator/filters/favorite-filters',
- 'navigator/filters/range-filters',
- 'navigator/filters/context-filters',
- 'navigator/filters/read-only-filters',
- 'navigator/filters/action-plan-filters',
- 'navigator/filters/rule-filters',
-
- 'common/handlebars-extensions'
- ],
- function (Backbone, Marionette, Handlebars, Extra, FilterBar, BaseFilters, CheckboxFilterView,
- ChoiceFilters, AjaxSelectFilters, FavoriteFilters, RangeFilters, ContextFilterView,
- ReadOnlyFilterView, ActionPlanFilterView, RuleFilterView) {
- Handlebars.registerPartial('detailInnerTemplate', jQuery('#issue-detail-inner-template').html());
-
- var NavigatorApp = new Marionette.Application();
-
-
- NavigatorApp.addRegions({
- headerRegion: '.navigator-header',
- filtersRegion: '.navigator-filters',
- resultsRegion: '.navigator-results',
- actionsRegion: '.navigator-actions',
- detailsRegion: '.navigator-details'
- });
-
-
- NavigatorApp.addInitializer(function () {
- jQuery('html').addClass('navigator-page issues-page');
-
- this.appState = new Extra.AppState();
- window.SS.appState = this.appState;
-
- this.state = new Backbone.Model({
- query: ''
- });
-
- this.issues = new Extra.Issues();
- this.issues.sorting = {
- sort: 'UPDATE_DATE',
- asc: false
- };
- this.issuesPage = 1;
-
- this.filters = new BaseFilters.Filters();
-
- this.favoriteFilter = new Extra.FavoriteFilter();
- this.issuesHeaderView = new Extra.IssuesHeaderView({
- app: this,
- model: this.favoriteFilter
- });
- this.headerRegion.show(this.issuesHeaderView);
-
- this.issuesView = new Extra.IssuesView({
- app: this,
- collection: this.issues
- });
- this.resultsRegion.show(this.issuesView);
-
- this.issuesActionsView = new Extra.IssuesActionsView({
- app: this,
- collection: this.issues
- });
- this.actionsRegion.show(this.issuesActionsView);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.projectFilter = new BaseFilters.Filter({
- name: window.SS.phrases.project,
- property: 'componentRoots',
- type: AjaxSelectFilters.ProjectFilterView,
- enabled: true,
- optional: false
- });
- this.filters.add(this.projectFilter);
-
- this.assigneeChoices = {
- '!assigned': window.SS.phrases.unassigned
- };
- this.reporterChoices = {};
- if (window.SS.currentUser) {
- this.assigneeChoices[window.SS.currentUser] = window.SS.currentUserName + ' (' + window.SS.currentUser + ')';
- this.reporterChoices[window.SS.currentUser] = window.SS.currentUserName + ' (' + window.SS.currentUser + ')';
- }
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.severity,
- property: 'severities',
- type: ChoiceFilters.ChoiceFilterView,
- enabled: true,
- optional: false,
- choices: {
- 'BLOCKER': window.SS.phrases.severities.BLOCKER,
- 'CRITICAL': window.SS.phrases.severities.CRITICAL,
- 'MAJOR': window.SS.phrases.severities.MAJOR,
- 'MINOR': window.SS.phrases.severities.MINOR,
- 'INFO': window.SS.phrases.severities.INFO
- },
- choiceIcons: {
- 'BLOCKER': 'severity-blocker',
- 'CRITICAL': 'severity-critical',
- 'MAJOR': 'severity-major',
- 'MINOR': 'severity-minor',
- 'INFO': 'severity-info'
- }
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.status,
- property: 'statuses',
- type: ChoiceFilters.ChoiceFilterView,
- enabled: true,
- optional: false,
- choices: {
- 'OPEN': window.SS.phrases.statuses.OPEN,
- 'CONFIRMED': window.SS.phrases.statuses.CONFIRMED,
- 'REOPENED': window.SS.phrases.statuses.REOPENED,
- 'RESOLVED': window.SS.phrases.statuses.RESOLVED,
- 'CLOSED': window.SS.phrases.statuses.CLOSED
- },
- choiceIcons: {
- 'OPEN': 'status-open',
- 'CONFIRMED': 'status-confirmed',
- 'REOPENED': 'status-reopened',
- 'RESOLVED': 'status-resolved',
- 'CLOSED': 'status-closed'
- }
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.assignee,
- property: 'assignees',
- type: AjaxSelectFilters.AssigneeFilterView,
- enabled: true,
- optional: false,
- choices: this.assigneeChoices
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.resolution,
- property: 'resolutions',
- type: ChoiceFilters.ChoiceFilterView,
- enabled: true,
- optional: false,
- choices: {
- '!resolved=true': window.SS.phrases.resolutions.RESOLVED,
- '!resolved=false': window.SS.phrases.resolutions.UNRESOLVED,
- 'FALSE-POSITIVE': window.SS.phrases.resolutions['FALSE-POSITIVE'],
- 'FIXED': window.SS.phrases.resolutions.FIXED,
- 'REMOVED': window.SS.phrases.resolutions.REMOVED
- }
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.actionPlan,
- property: 'actionPlans',
- type: ActionPlanFilterView,
- enabled: false,
- optional: true,
- projectFilter: this.projectFilter,
- choices: {
- '!planned': window.SS.phrases.unplanned
- }
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.created,
- propertyFrom: 'createdAfter',
- propertyTo: 'createdBefore',
- type: RangeFilters.DateRangeFilterView,
- enabled: false,
- optional: true
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.createdAt,
- property: 'createdAt',
- type: ReadOnlyFilterView,
- enabled: false,
- optional: true,
- format: function(value) { return moment(value).format('YYYY-MM-DD HH:mm'); }
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.language,
- property: 'languages',
- type: ChoiceFilters.ChoiceFilterView,
- enabled: false,
- optional: true,
- choices: window.SS.languages
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.reporter,
- property: 'reporters',
- type: AjaxSelectFilters.ReporterFilterView,
- enabled: false,
- optional: true,
- choices: this.reporterChoices
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filters.add([
- new BaseFilters.Filter({
- name: window.SS.phrases.rule,
- property: 'rules',
- type: RuleFilterView,
- enabled: false,
- optional: true
- })
- ]);
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.filterBarView = new Extra.IssuesFilterBarView({
- app: this,
- collection: this.filters,
- extra: {
- sort: '',
- asc: false
- }
- });
-
- this.filtersRegion.show(this.filterBarView);
- });
-
-
- NavigatorApp.addInitializer(function () {
- var app = this;
-
- jQuery.when(this.appState.fetch()).done(function () {
-
- if (app.appState.get('favorites')) {
- app.filters.unshift(
- new BaseFilters.Filter({
- type: Extra.IssuesFavoriteFilterView,
- enabled: true,
- optional: false,
- choices: app.appState.get('favorites'),
- manageUrl: '/issues/manage'
- })
- );
- }
-
- app.router = new Extra.IssuesRouter({
- app: app
- });
- Backbone.history.start();
-
- app.favoriteFilter.on('change:query', function (model, query) {
- app.router.navigate(query, { trigger: true, replace: true });
- });
- });
- });
-
-
- NavigatorApp.addInitializer(function () {
- var app = this;
-
- window.onBulkIssues = function () {
- app.fetchFirstPage();
- jQuery('#modal').dialog('close');
- };
-
- window.onSaveAs = window.onCopy = window.onEdit = function (id) {
- jQuery('#modal').dialog('close');
- app.appState.fetch();
-
- var filter = new Extra.FavoriteFilter({ id: id });
- filter.fetch({
- success: function () {
- app.state.set('search', false);
- app.favoriteFilter.set(filter.toJSON());
- app.fetchFirstPage();
- }
- });
- };
- });
-
-
- NavigatorApp.addInitializer(function () {
- this.onResize = function() {
- var footerEl = jQuery('#footer'),
- footerHeight = footerEl.outerHeight(true);
-
- var resultsEl = jQuery('.navigator-results'),
- resultsHeight = jQuery(window).height() - resultsEl.offset().top -
- parseInt(resultsEl.css('margin-bottom'), 10) - footerHeight;
- resultsEl.height(resultsHeight);
-
- var detailsEl = jQuery('.navigator-details'),
- detailsWidth = jQuery(window).width() - detailsEl.offset().left -
- parseInt(detailsEl.css('margin-right'), 10) - 20,
- detailsHeight = jQuery(window).height() - detailsEl.offset().top -
- parseInt(detailsEl.css('margin-bottom'), 10) - footerHeight;
- detailsEl.width(detailsWidth).height(detailsHeight);
-
- var resultsLoadingEl = jQuery('.navigator-results-loader');
- resultsLoadingEl
- .css('top', resultsEl.offset().top)
- .css('left', resultsEl.offset().left)
- .width(resultsEl.width() + 10)
- .height(resultsEl.height() + 10);
- };
- jQuery(window).on('resize', this.onResize);
- this.onResize();
- });
-
-
- NavigatorApp.addInitializer(function () {
- var that = this;
- jQuery('body')
- .on('mousemove', function (e) {
- that.processResize(e);
- })
- .on('mouseup', function () {
- that.stopResize();
- });
- jQuery('.navigator-resizer').on('mousedown', function (e) {
- that.startResize(e);
- });
-
- var resultsWidth = localStorage.getItem('issuesResultsWidth');
- if (resultsWidth) {
- jQuery('.navigator-results').width(+resultsWidth);
- jQuery('.navigator-side').width(+resultsWidth + 20);
- this.onResize();
- }
- });
-
-
- NavigatorApp.startResize = function (e) {
- this.isResize = true;
- this.originalWidth = jQuery('.navigator-results').width();
- this.x = e.clientX;
- jQuery('html').attr('unselectable', 'on').css('user-select', 'none').on('selectstart', false);
- };
-
-
- NavigatorApp.processResize = function (e) {
- if (this.isResize) {
- var delta = e.clientX - this.x;
- jQuery('.navigator-results').width(this.originalWidth + delta);
- jQuery('.navigator-side').width(this.originalWidth + 20 + delta);
- localStorage.setItem('issuesResultsWidth', jQuery('.navigator-results').width());
- this.onResize();
- }
- };
-
-
- NavigatorApp.stopResize = function() {
- if (this.isResize) {
- jQuery('html').attr('unselectable', 'off').css('user-select', 'text').off('selectstart');
- }
- this.isResize = false;
- };
-
-
- NavigatorApp.getQuery = function (withoutId) {
- if (this.filterBarView) {
- var query = this.filterBarView.getQuery();
- if (!withoutId && this.favoriteFilter.id) {
- query['id'] = this.favoriteFilter.id;
- }
- return query;
- } else {
- return {};
- }
- };
-
-
- NavigatorApp.storeQuery = function (query, sorting) {
- if (sorting) {
- _.extend(query, {
- sort: sorting.sort,
- asc: '' + sorting.asc
- });
- }
-
- var queryString = _.map(query,function (v, k) {
- return [k, encodeURIComponent(v)].join('=');
- }).join('|');
- this.router.navigate(queryString, { replace: true });
- };
-
-
- NavigatorApp.restoreSorting = function (query) {
- var sort = _.findWhere(query, { key: 'sort' }),
- asc = _.findWhere(query, { key: 'asc' });
-
- if (sort && asc) {
- this.issues.sorting = {
- sort: sort.value,
- sortText: jQuery('[data-sort=' + sort.value + ']:first').text(),
- asc: asc.value === 'true'
- };
- }
- };
-
-
- NavigatorApp.fetchIssues = function (firstPage) {
- var query = this.getQuery(),
- fetchQuery = _.extend({
- pageIndex: this.issuesPage
- }, query);
-
- // SONAR-5086
- if (fetchQuery['actionPlans'] && fetchQuery['componentRoots']) {
- delete fetchQuery['componentRoots'];
- }
-
- if (this.issues.sorting) {
- _.extend(fetchQuery, {
- sort: this.issues.sorting.sort,
- asc: this.issues.sorting.asc
- });
- }
-
- _.extend(fetchQuery, {
- hideRules: true
- });
-
- if (this.favoriteFilter.id) {
- query['id'] = this.favoriteFilter.id;
- fetchQuery['id'] = this.favoriteFilter.id;
- }
-
- this.storeQuery(query, this.issues.sorting);
-
- var that = this;
- jQuery('.navigator-results').addClass('fetching');
- if (firstPage) {
- this.issues.fetch({
- data: fetchQuery,
- success: function () {
- jQuery('.navigator-results').removeClass('fetching');
- that.issuesView.selectFirst();
- }
- });
- this.detailsRegion.reset();
- } else {
- this.issues.fetch({
- data: fetchQuery,
- remove: false,
- success: function () {
- jQuery('.navigator-results').removeClass('fetching');
- }
- });
- }
- };
-
-
- NavigatorApp.fetchFirstPage = function () {
- this.issuesPage = 1;
- this.fetchIssues(true);
- };
-
-
- NavigatorApp.fetchNextPage = function () {
- if (this.issuesPage < this.issues.paging.pages) {
- this.issuesPage++;
- this.fetchIssues(false);
- }
- };
-
- window.requestMessages().done(function () {
- NavigatorApp.start();
- });
-
- });
+++ /dev/null
-define(
- [
- 'backbone',
- 'backbone.marionette',
- 'navigator/filters/filter-bar',
- 'navigator/filters/base-filters',
- 'navigator/filters/favorite-filters',
- 'navigator/filters/read-only-filters',
- 'component-viewer/main',
- 'templates/issues'
- ],
- function (Backbone, Marionette, FilterBarView, BaseFilters, FavoriteFiltersModule, ReadOnlyFilterView,
- ComponentViewer, Templates) {
-
- var AppState = Backbone.Model.extend({
-
- defaults: {
- canManageFilters: false,
- canBulkChange: false
- },
-
-
- url: function () {
- return baseUrl + '/api/issue_filters/app';
- }
-
- });
-
-
- var Issue = Backbone.Model.extend({
-
- url: function () {
- return baseUrl + '/api/issues/show?key=' + this.get('key');
- },
-
-
- parse: function (r) {
- return r.issue ? r.issue : r;
- }
-
- });
-
-
- var Issues = Backbone.Collection.extend({
- model: Issue,
-
-
- url: function () {
- return baseUrl + '/api/issues/search';
- },
-
-
- parse: function (r) {
-
- function find(source, key, keyField) {
- var searchDict = {};
- searchDict[keyField || 'key'] = key;
- return _.findWhere(source, searchDict) || key;
- }
-
- this.paging = r.paging;
- this.maxResultsReached = r.maxResultsReached;
-
- return r.issues.map(function (issue) {
- var component = find(r.components, issue.component),
- project = find(r.projects, issue.project),
- rule = find(r.rules, issue.rule);
-
- if (component) {
- _.extend(issue, {
- componentLongName: component.longName,
- componentQualifier: component.qualifier
- });
- }
-
- if (project) {
- _.extend(issue, {
- projectLongName: project.longName
- });
- }
-
- if (rule) {
- _.extend(issue, {
- ruleName: rule.name
- });
- }
-
- return issue;
- });
-
- }
- });
-
-
- var FavoriteFilter = Backbone.Model.extend({
-
- url: function () {
- return baseUrl + '/api/issue_filters/show/' + this.get('id');
- },
-
-
- parse: function (r) {
- return r.filter ? r.filter : r;
- }
- });
-
-
- var FavoriteFilters = Backbone.Collection.extend({
- model: FavoriteFilter,
-
-
- url: function () {
- return baseUrl + '/api/issue_filters/favorites';
- },
-
-
- parse: function (r) {
- return r.favoriteFilters;
- }
- });
-
-
- var IssueView = Marionette.ItemView.extend({
- template: Templates['issue-detail'],
- tagName: 'li',
-
-
- ui: {
- component: '.component'
- },
-
-
- events: {
- 'click': 'showDetails'
- },
-
-
- modelEvents: {
- 'change': 'render'
- },
-
-
- showDetails: function () {
- key.setScope('list');
- this.options.issuesView.selected = this.$el.parent().children().index(this.$el);
-
- this.options.issuesView.selectIssue(this.$el, false);
-
- var that = this,
- app = this.options.app,
- settings = localStorage.getItem('componentViewerSettings'),
- navigatorDetails = jQuery('.navigator-details'),
- componentViewer = new ComponentViewer({
- settings: settings,
- shouldStoreSettings: true,
- elementToFit: navigatorDetails,
- component: {
- project: this.model.get('project'),
- projectLongName: this.model.get('projectLongName')
- }
- }),
- showCallback = function () {
- navigatorDetails.removeClass('navigator-fetching');
- app.detailsRegion.show(componentViewer);
- componentViewer.settings.set('issues', false);
- componentViewer.open(that.model.get('component'));
- componentViewer.on('loaded', function() {
- componentViewer.off('loaded');
- componentViewer.showIssues(false, that.model.toJSON());
- });
- };
-
- navigatorDetails.empty().addClass('navigator-fetching');
- var issueKey = this.model.get('key');
- this.model.clear({ silent: true });
- this.model.set({ key: issueKey }, { silent: true });
- jQuery.when(this.model.fetch()).done(showCallback);
- },
-
-
- serializeData: function () {
- var projectFilter = this.options.app.filters.findWhere({ property: 'componentRoots' }),
- singleProject = _.isArray(projectFilter.get('value')) && projectFilter.get('value').length === 1;
-
- return _.extend({
- singleProject: singleProject
- }, this.model.toJSON());
- }
- });
-
-
- var NoIssuesView = Marionette.ItemView.extend({
- tagName: 'li',
- className: 'navigator-results-no-results',
- template: Templates['no-issues']
- });
-
-
- var IssuesView = Marionette.CompositeView.extend({
- template: Templates['issues'],
- itemViewContainer: '.navigator-results-list',
- itemView: IssueView,
- emptyView: NoIssuesView,
-
-
- initialize: function() {
- var openIssue = function(el) {
- el.click();
- };
- this.openIssue = _.debounce(openIssue, 300);
- },
-
-
- itemViewOptions: function () {
- return {
- issuesView: this,
- app: this.options.app
- };
- },
-
-
- selectIssue: function(el, open) {
- this.$('.active').removeClass('active');
- el.addClass('active');
- if (open) {
- this.openIssue(el);
- }
- },
-
-
- selectFirst: function() {
- this.selected = -1;
- this.selectNext();
- },
-
-
- selectNext: function() {
- if (this.selected < this.collection.length - 1) {
- this.selected++;
- var child = this.$(this.itemViewContainer).children().eq(this.selected),
- container = jQuery('.navigator-results'),
- containerHeight = container.height(),
- bottom = child.position().top + child.outerHeight();
- if (bottom > containerHeight) {
- container.scrollTop(container.scrollTop() - containerHeight + bottom);
- }
- this.selectIssue(child, true);
- }
- },
-
-
- selectPrev: function() {
- if (this.selected > 0) {
- this.selected--;
- var child = this.$(this.itemViewContainer).children().eq(this.selected),
- container = jQuery('.navigator-results'),
- top = child.position().top;
- if (top < 0) {
- container.scrollTop(container.scrollTop() + top);
- }
- this.selectIssue(child, true);
- }
- },
-
-
- onRender: function () {
- var that = this,
- $scrollEl = jQuery('.navigator-results'),
- scrollEl = $scrollEl.get(0),
- onScroll = function () {
- if (scrollEl.offsetHeight + scrollEl.scrollTop >= scrollEl.scrollHeight) {
- that.options.app.fetchNextPage();
- }
- },
- throttledScroll = _.throttle(onScroll, 300);
- $scrollEl.off('scroll').on('scroll', throttledScroll);
- this.bindShortcuts();
- },
-
-
- onAfterItemAdded: function () {
- var showLimitNotes = this.collection.maxResultsReached != null && this.collection.maxResultsReached;
- jQuery('.navigator').toggleClass('navigator-with-notes', showLimitNotes);
- jQuery('.navigator-notes').toggle(showLimitNotes);
- },
-
-
- close: function () {
- var scrollEl = jQuery('.navigator-results');
- scrollEl.off('scroll');
- Marionette.CollectionView.prototype.close.call(this);
- },
-
-
- bindShortcuts: function () {
- var that = this;
- key('up', 'list', function() {
- that.selectPrev();
- });
- key('down', 'list', function() {
- that.selectNext();
- });
- }
-
- });
-
-
- var IssuesActionsView = Marionette.ItemView.extend({
- template: Templates['issues-actions'],
-
-
- collectionEvents: {
- 'sync': 'render'
- },
-
-
- events: {
- 'click .navigator-actions-order': 'toggleOrderChoices',
- 'click .navigator-actions-order-choices': 'sort',
- 'click .navigator-actions-bulk': 'bulkChange'
- },
-
-
- ui: {
- orderChoices: '.navigator-actions-order-choices'
- },
-
-
- onRender: function () {
- if (!this.collection.sorting.sortText) {
- this.collection.sorting.sortText = this.$('[data-sort=' + this.collection.sorting.sort + ']:first').text();
- this.$('.navigator-actions-ordered-by').text(this.collection.sorting.sortText);
- }
- },
-
-
- toggleOrderChoices: function (e) {
- e.stopPropagation();
- this.ui.orderChoices.toggleClass('open');
- if (this.ui.orderChoices.is('.open')) {
- var that = this;
- jQuery('body').on('click.issues_actions', function () {
- that.ui.orderChoices.removeClass('open');
- });
- }
- },
-
-
- sort: function (e) {
- e.stopPropagation();
- this.ui.orderChoices.removeClass('open');
- jQuery('body').off('click.issues_actions');
- var el = jQuery(e.target),
- sort = el.data('sort'),
- asc = el.data('asc');
-
- if (sort != null && asc != null) {
- this.collection.sorting = {
- sort: sort,
- sortText: el.text(),
- asc: asc
- };
- this.options.app.fetchFirstPage();
- }
- },
-
-
- bulkChange: function(e) {
- e.preventDefault();
- openModalWindow(jQuery(e.currentTarget).prop('href'), {});
- },
-
-
- serializeData: function () {
- var data = Marionette.ItemView.prototype.serializeData.apply(this, arguments),
- bulkChangeData = this.options.app.getQuery(true),
- bulkChangeQuery = _.map(bulkChangeData,function (v, k) {
- return [k, encodeURIComponent(v)].join('=');
- }).join('&');
- return _.extend(data || {}, {
- paging: this.collection.paging,
- sorting: this.collection.sorting,
- maxResultsReached: this.collection.maxResultsReached,
- appState: window.SS.appState.toJSON(),
- bulkChangeUrl: baseUrl + '/issues/bulk_change_form',
- query: bulkChangeQuery
- });
- }
- });
-
-
-
- var IssuesDetailsFavoriteFilterView = FavoriteFiltersModule.DetailsFavoriteFilterView.extend({
- template: Templates['issues-details-favorite-filter'],
-
-
- applyFavorite: function (e) {
- var id = $j(e.target).data('id'),
- filter = new FavoriteFilter({ id: id }),
- app = this.options.filterView.options.app;
-
- filter.fetch({
- success: function () {
- app.state.set('search', false);
- app.favoriteFilter.clear({ silent: true });
- app.favoriteFilter.set(filter.toJSON());
- }
- });
-
- this.options.filterView.hideDetails();
- },
-
-
- serializeData: function () {
- return _.extend({}, this.model.toJSON(), {
- items: _.sortBy(this.model.get('choices'), function(item) {
- return item.name.toLowerCase();
- })
- });
- }
- });
-
-
-
- var IssuesFavoriteFilterView = FavoriteFiltersModule.FavoriteFilterView.extend({
-
- initialize: function () {
- BaseFilters.BaseFilterView.prototype.initialize.call(this, {
- detailsView: IssuesDetailsFavoriteFilterView
- });
-
- this.listenTo(window.SS.appState, 'change:favorites', this.updateFavorites);
- },
-
-
- updateFavorites: function () {
- this.model.set('choices', window.SS.appState.get('favorites'));
- this.render();
- }
- });
-
-
-
- var IssuesFilterBarView = FilterBarView.extend({
- template: Templates['filter-bar'],
-
- collectionEvents: {
- 'change:enabled': 'changeEnabled'
- },
-
-
- events: {
- 'click .navigator-filter-submit': 'search'
- },
-
-
- getQuery: function () {
- var query = {};
- this.collection.each(function (filter) {
- _.extend(query, filter.view.formatValue());
- });
- return query;
- },
-
-
- onAfterItemAdded: function (itemView) {
- if (itemView.model.get('type') === FavoriteFiltersModule.FavoriteFilterView ||
- itemView.model.get('type') === IssuesFavoriteFilterView) {
- jQuery('.navigator-header').addClass('navigator-header-favorite');
- }
- },
-
-
- addMoreCriteriaFilter: function() {
- var readOnlyFilters = this.collection.where({ type: ReadOnlyFilterView }),
- disabledFilters = _.difference(this.collection.where({ enabled: false }), readOnlyFilters);
- this.moreCriteriaFilter = new BaseFilters.Filter({
- type: require('navigator/filters/more-criteria-filters').MoreCriteriaFilterView,
- enabled: true,
- optional: false,
- filters: disabledFilters
- });
- this.collection.add(this.moreCriteriaFilter);
- },
-
-
- changeEnabled: function () {
- var disabledFilters = _.reject(this.collection.where({ enabled: false }), function (filter) {
- return filter.get('type') ===
- require('navigator/filters/more-criteria-filters').MoreCriteriaFilterView ||
- filter.get('type') === ReadOnlyFilterView;
- });
-
- if (disabledFilters.length === 0) {
- this.moreCriteriaFilter.set({ enabled: false }, { silent: true });
- } else {
- this.moreCriteriaFilter.set({ enabled: true }, { silent: true });
- }
- this.moreCriteriaFilter.set({ filters: disabledFilters }, { silent: true });
- this.moreCriteriaFilter.trigger('change:filters');
- },
-
-
- search: function () {
- this.$('.navigator-filter-submit').blur();
- this.options.app.state.set({
- query: this.options.app.getQuery(),
- search: true
- });
- this.options.app.fetchFirstPage();
- },
-
-
- fetchNextPage: function () {
- this.options.app.fetchNextPage();
- }
-
- });
-
-
- var IssuesHeaderView = Marionette.ItemView.extend({
- template: Templates['issues-header'],
-
-
- modelEvents: {
- 'change': 'render'
- },
-
-
- events: {
- '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'
- },
-
-
- initialize: function (options) {
- Marionette.ItemView.prototype.initialize.apply(this, arguments);
- this.listenTo(options.app.state, 'change', this.render);
- },
-
-
- newSearch: function () {
- this.model.clear();
- this.options.app.router.navigate('resolved=false', { trigger: true, replace: true });
- },
-
-
- saveAs: function () {
- var url = baseUrl + '/issues/save_as_form?' + (Backbone.history.fragment || '').replace(/\|/g, '&');
- openModalWindow(url, {});
- },
-
-
- save: function () {
- var that = this;
- url = baseUrl + '/issues/save/' + this.model.id + '?' + (Backbone.history.fragment || '').replace(/\|/g, '&');
- jQuery.ajax({
- type: 'POST',
- url: url
- }).done(function () {
- that.options.app.state.set('search', false);
- });
- },
-
-
- copy: function () {
- var url = baseUrl + '/issues/copy_form/' + this.model.id;
- openModalWindow(url, {});
- },
-
-
- edit: function () {
- var url = baseUrl + '/issues/edit_form/' + this.model.id;
- openModalWindow(url, {});
- },
-
-
- serializeData: function () {
- return _.extend({
- canSave: this.model.id && this.options.app.state.get('search'),
- appState: window.SS.appState.toJSON(),
- currentUser: window.SS.currentUser
- }, this.model.toJSON());
- }
-
- });
-
-
-
- var IssuesRouter = Backbone.Router.extend({
-
- routes: {
- '': 'emptyQuery',
- ':query': 'index'
- },
-
-
- initialize: function (options) {
- this.app = options.app;
- },
-
-
- parseQuery: function (query, separator) {
- return (query || '').split(separator || '|').map(function (t) {
- var tokens = t.split('=');
- return {
- key: tokens[0],
- value: decodeURIComponent(tokens[1])
- };
- });
- },
-
-
- emptyQuery: function () {
- this.navigate('resolved=false', { trigger: true, replace: true });
- },
-
-
- index: function (query) {
- var params = this.parseQuery(query);
-
- var idObj = _.findWhere(params, { key: 'id' });
- if (idObj) {
- var that = this,
- f = this.app.favoriteFilter;
- this.app.canSave = false;
- f.set('id', idObj.value);
- f.fetch({
- success: function () {
- var parsedFilter = that.parseQuery(f.get('query'));
- params = _.extend({}, params);
- params = _.extent(params, parsedFilter);
- that.loadResults(params);
- }
- });
- } else {
- this.loadResults(params);
- }
- },
-
-
- loadResults: function (params) {
- this.app.filterBarView.restoreFromQuery(params);
- this.app.restoreSorting(params);
- this.app.fetchFirstPage();
- }
-
- });
-
-
- /*
- * Export public classes
- */
-
- return {
- AppState: AppState,
- Issue: Issue,
- Issues: Issues,
- FavoriteFilter: FavoriteFilter,
- FavoriteFilters: FavoriteFilters,
- IssueView: IssueView,
- IssuesView: IssuesView,
- IssuesActionsView: IssuesActionsView,
- IssuesFilterBarView: IssuesFilterBarView,
- IssuesHeaderView: IssuesHeaderView,
- IssuesFavoriteFilterView: IssuesFavoriteFilterView,
- IssuesRouter: IssuesRouter
- };
-
- });
@import (reference) 'variables';
@import (reference) 'mixins';
-.component-viewer-source {
-
- .code pre {
- padding: 0;
- font-family: 'Source Code Pro', monospace;
- font-size: 12px;
- line-height: 16px;
- }
-
- /* constants */
- .code .c {
- font-style: normal;
- }
-
- /* javadoc */
- .code .j {
- font-style: normal;
- }
-
- /* keyword */
- .code .k {
- color: saturate(@darkBlue, 50%);
- font-weight: 600;
- }
+.code pre {
+ padding: 0;
+ font-family: 'Source Code Pro', monospace;
+ font-size: 12px;
+ line-height: 16px;
+}
- /* string */
- .code .s {
- color: saturate(@red, 0%);
- font-weight: normal;
- }
+/* constants */
+.code .c {
+ font-style: normal;
+}
- /* preprocessing directive */
- .code .p {
- font-weight: normal;
- }
+/* javadoc */
+.code .j {
+ font-style: normal;
+}
- .sym {
- @symColor: darken(saturate(@green, 10%), 15%);
- border-bottom: 1px dotted @symColor;
- .trans(color);
+/* keyword */
+.code .k {
+ color: saturate(@darkBlue, 50%);
+ font-weight: 600;
+}
- &:hover,
- &.highlighted { color: @symColor; }
- }
+/* string */
+.code .s {
+ color: saturate(@red, 0%);
+ font-weight: normal;
+}
+/* preprocessing directive */
+.code .p {
+ font-weight: normal;
}
&:hover { background-color: @barBorderColor; }
}
-
.component-viewer-source {
position: relative;
float: left;
overflow: auto;
}
- .code {
- width: 100%;
- border: 1px solid @barBorderColor;
- }
-
.code th {
- height: 30px;
- .box-sizing(border-box);
- background-color: @barBackgroundColor;
-
- &.stat {
- padding-top: 4px;
- padding-bottom: 4px;
- border-left: none;
- border-right: none;
- border-bottom: 1px solid @barBorderColor;
- }
-
- &.lid {
- border-right: 1px solid @barBorderColor;
- }
&.settings {
line-height: 22px;
}
}
- .code .row:hover {
- td.stat { background-color: @barBorderColor; }
- td.line { background-color: @barBackgroundColor; }
- }
-
- .code .row-highlighted,
- .code .row-highlighted:hover {
- td.stat { background-color: #fdf190; }
- td.line, .code-issues, .code-issue { background-color: #fff8c2; }
- }
-
- .code td.line {
- width: 100%;
- padding: 1px 5px;
- }
-
- .code .stat {
- vertical-align: top;
- min-width: 12px;
- padding: 1px 5px;
- background-color: @barBackgroundColor;
- color: #888;
- font-size: 11px;
- line-height: 16px;
- text-align: right;
- cursor: default;
- white-space: nowrap;
- }
-
- .code .lid {
- min-width: 18px;
- padding-left: 10px;
- padding-right: 10px;
- cursor: pointer;
- }
-
.code .coverage-tests {
cursor: pointer;
}
background-color: @barBackgroundColor;
}
- .code .issue > pre {
- display: inline-block;
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAGCAYAAAAPDoR2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1M0M2Rjk4M0M3QUYxMUUzODkzRUREMUM5OTNDMjY4QSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1M0M2Rjk4NEM3QUYxMUUzODkzRUREMUM5OTNDMjY4QSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjUzQzZGOTgxQzdBRjExRTM4OTNFREQxQzk5M0MyNjhBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjUzQzZGOTgyQzdBRjExRTM4OTNFREQxQzk5M0MyNjhBIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+bcqJtQAAAEhJREFUeNpi+G+swwDGDAwgbAWlwZiJAQFCgfgwEIfDRaC67ID4NRDnQ2kQnwFZwgFqnANMAQOUYY9sF0wBiCGH5CBkrAgQYACuWi4sSGW8yAAAAABJRU5ErkJggg==);
- background-repeat: repeat-x;
- background-size: 4px;
- background-position: bottom;
- }
-
- .code .scm {
- line-height: 16px;
- padding-top: 0;
- padding-bottom: 0;
- text-align: left;
-
- .scm-date {
- display: inline-block;
- vertical-align: middle;
- padding: 2px 4px;
- line-height: 1;
- background-color: @barBorderColor;
- }
-
- .scm-author {
- display: inline-block;
- vertical-align: middle;
- max-width: 120px;
- padding: 2px 0;
- line-height: 1;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- }
-
.code .stat {
&.coverage-green {
--- /dev/null
+@import "components/component-issues";
+@import "components/code-source";
+@import "components/facets";
--- /dev/null
+@import (reference) "../mixins";
+@import (reference) "../variables";
+
+.code-source {
+
+ .code {
+ width: 100%;
+ border: 1px solid @barBorderColor;
+ }
+
+ .code th {
+ height: 30px;
+ .box-sizing(border-box);
+ background-color: @barBackgroundColor;
+
+ &.lid {
+ border-right: 1px solid @barBorderColor;
+ }
+
+ &.stat {
+ padding-top: 4px;
+ padding-bottom: 4px;
+ border-left: none;
+ border-right: none;
+ border-bottom: 1px solid @barBorderColor;
+ }
+ }
+
+ .code .stat {
+ vertical-align: top;
+ min-width: 12px;
+ padding: 1px 5px;
+ background-color: @barBackgroundColor;
+ color: #888;
+ font-size: 11px;
+ line-height: 16px;
+ text-align: right;
+ cursor: default;
+ white-space: nowrap;
+ }
+
+ .code .lid {
+ min-width: 18px;
+ padding-left: 10px;
+ padding-right: 10px;
+ cursor: pointer;
+ }
+
+ .code .scm {
+ line-height: 16px;
+ padding-top: 0;
+ padding-bottom: 0;
+ text-align: left;
+
+ .scm-date {
+ display: inline-block;
+ vertical-align: middle;
+ padding: 2px 4px;
+ line-height: 1;
+ background-color: @barBorderColor;
+ }
+
+ .scm-author {
+ display: inline-block;
+ vertical-align: middle;
+ max-width: 120px;
+ padding: 2px 0;
+ line-height: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ }
+
+ .code .row:hover {
+ td.stat { background-color: @barBorderColor; }
+ td.line { background-color: @barBackgroundColor; }
+ }
+
+ .code .row-highlighted,
+ .code .row-highlighted:hover {
+ td.stat { background-color: #fdf190; }
+ td.line, .code-issues, .code-issue { background-color: #fff8c2; }
+ }
+
+ .code td.line {
+ width: 100%;
+ padding: 1px 5px;
+ }
+
+}
--- /dev/null
+@import (reference) "../variables";
+@import (reference) "../mixins";
+
+.issues-distribution-bar {
+ display: inline-block;
+ vertical-align: middle;
+ width: 45px;
+}
+
+.issues-distribution-bar-item {
+ display: block;
+ min-width: 1px;
+ height: 3px;
+
+ &.s-blocker { background-color: @severityBlockerColor; }
+ &.s-critical { background-color: @severityCriticalColor; }
+ &.s-major { background-color: @severityMajorColor; }
+ &.s-minor { background-color: @severityMinorColor; }
+ &.s-info { background-color: @severityInfoColor; }
+}
+
+.issues-distribution-bar-item + .issues-distribution-bar-item {
+ margin-top: 1px;
+}
--- /dev/null
+@import (reference) "../mixins";
+@import (reference) "../variables";
+
+.facet {
+ display: inline-block;
+ vertical-align: middle;
+ line-height: 1;
+ margin: 0 6px 6px 6px;
+ padding: 4px 5px;
+ border: 1px solid @barBorderColor;
+ border-radius: 2px;
+ background-color: lighten(@barBackgroundColor, 2%);
+ font-size: 0;
+ font-weight: 300;
+ cursor: pointer;
+ white-space: nowrap;
+ .trans(none);
+
+ &:hover {
+ border: 1px solid @blue;
+ text-decoration: none;
+ }
+
+ &.active {
+ border: 1px solid @blue;
+ background-color: @lightBlue;
+ text-decoration: none;
+
+ .facet-name {
+ background-color: @lightBlue;
+ }
+
+ .facet-stat {
+ border-color: @blue;
+ background-color: @lightBlue;
+ }
+ }
+}
+
+.facet-name {
+ background-color: lighten(@barBackgroundColor, 2%);
+ font-size: @smallFontSize;
+}
+
+.facet-stat {
+ margin-left: 5px;
+ padding-left: 5px;
+ border-left: 1px solid @barBorderColor;
+ background-color: lighten(@barBackgroundColor, 2%);
+ color: @secondFontColor;
+ font-size: @smallFontSize;
+}
}
.icon-bulk-change:before {
content: "\f085";
- font-size: @iconFontSize;
+ font-size: @iconSmallFontSize;
}
.icon-arrow-down:before {
content: "\f0d7";
color: @red;
font-size: @iconFontSize;
}
+.icon-close:before {
+ content: "\f00d";
+ font-size: @iconFontSize;
+}
.icon-compare:before {
content: "\f0c5";
font-size: @iconSmallFontSize;
color: #999;
font-size: @iconSmallFontSize;
}
+.icon-filters:before {
+ content: "\f039";
+ font-size: @iconSmallFontSize;
+}
+.icon-next:before {
+ content: "\f0d7";
+ font-size: @iconFontSize;
+}
+.icon-prev:before {
+ content: "\f0d8";
+ font-size: @iconFontSize;
+}
/*
--- /dev/null
+@import (reference) "variables";
+@import (reference) "mixins";
+@import (reference) "ui";
+
+@sideWidth: 300px;
+
+
+.issues {
+
+ &.sticky {
+
+ .issues-workspace-header {
+ position: fixed;
+ z-index: 4;
+ top: 0;
+ left: @sideWidth;
+ right: 0px;
+ }
+
+ .issues-workspace-list,
+ .issues-workspace-component-viewer {
+ padding-top: 37px;
+ }
+
+ .issues-side {
+ position: fixed;
+ z-index: 4;
+ top: 0;
+ bottom: 0;
+ overflow-y: scroll;
+ }
+
+ }
+}
+
+.issues-side {
+ position: fixed;
+ width: @sideWidth;
+ top: 30px; left: 0; bottom: 0;
+ .box-sizing(border-box);
+ border-right: 1px solid @barBorderColor;
+ background-color: @barBorderColor;
+ color: #fff;
+ 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: 300;
+ }
+}
+
+.issues-facet {
+ position: relative;
+ width: @sideWidth - 22px;
+ margin: 0 22px 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: @secondFontColor;
+ }
+
+ .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, rgba(255, 255, 255, 0), @barBackgroundColor 75%);
+ }
+ }
+
+ &.active .facet-stat:before {
+ background-image: linear-gradient(to right, rgba(255, 255, 255, 0), @lightBlue 75%);
+ }
+}
+
+.issues-facet-half {
+ width: @sideWidth / 2 - 22px;
+}
+
+.issues-facet-header {
+ display: block;
+ padding: 6px 10px;
+ border-bottom: none;
+ color: @baseFontColor;
+ font-weight: 400;
+}
+
+.issues-facet-list {
+ margin: 0 -22px 0 0;
+ padding: 0 10px 10px;
+ font-size: 0;
+}
+
+.issues-facet-container {
+ margin-top: 6px;
+ padding: 0 10px 16px;
+}
+
+.issues-facet-input {
+ width: @sideWidth * 0.4;
+// .box-sizing(border-box);
+}
+
+.issues-filters {
+ .clearfix;
+ padding: 8px 10px;
+ background-color: @barBackgroundColor;
+ color: @secondFontColor;
+ font-size: @smallFontSize;
+ font-weight: 300;
+}
+
+.issues-filters-list {
+ display: none;
+ margin-bottom: 8px;
+ line-height: 1.5;
+}
+
+.issues-filters-filter {
+
+}
+
+.issues-filters-header {
+ font-size: @smallFontSize;
+ font-weight: 300;
+}
+
+.issues-filters-header-filters {
+ display: inline-block;
+ max-width: 50%;
+ .text-ellipsis;
+}
+
+.issues-filters-header-actions {
+ float: right;
+}
+
+.issues-filters-button {
+ border-bottom-color: @secondFontColor;
+ color: @secondFontColor;
+ font-size: @smallFontSize;
+ font-weight: 300;
+ .trans(color);
+
+ &:hover, &:active {
+ color: #fff;
+ }
+
+ &:focus {}
+}
+
+.issues-workspace {
+ padding-left: @sideWidth;
+}
+
+.issues-header {
+ .clearfix;
+ margin-bottom: 10px;
+ padding: 5px 0;
+ border: 1px solid @barBorderColor;
+ border-left: none;
+ background: @barBackgroundColor;
+ font-size: @smallFontSize;
+}
+
+.issues-header-item {
+ display: inline-block;
+ margin: 0 10px;
+}
+
+.issues-header-nav {
+ float: right;
+}
+
+.issues-workspace-list {
+ padding: 0 10px;
+}
+
+.issues-workspace-list-more {
+ margin-top: 10px;
+ padding: 5px 10px;
+ border: 1px solid @barBorderColor;
+ background: @barBackgroundColor;
+ text-align: center;
+}
+
+.issues-workspace-component-viewer {
+ padding: 0 10px;
+ overflow-x: auto;
+}
+
+.issues-workspace-component-viewer-header {
+ position: relative;
+}
+
+.issues-workspace-component-viewer-close {
+ position: absolute;
+ top: 50%;
+ right: 10px;
+ margin-top: -8px;
+}
+
+.issues-extended-view {
+
+ .issues-workspace-list {
+ display: none;
+ }
+}
+
+.issue-box {
+ .clearfix;
+ border: 1px solid @barBorderColor;
+ border-left: none;
+ overflow: hidden;
+
+ &.selected {
+ background-color: #e4ecf3;
+ }
+}
+
+.issue-box + .issue-box {
+ margin-top: 12px;
+}
+
+.issue-box-component,
+.issue-box-snippet {
+ border-left: 2px solid @red;
+}
+
+.issue-box-details {
+
+}
+
+.code-issue-modern {
+ border-left: 2px solid @red;
+
+ .code-issue-name,
+ .code-issue-actions,
+ .code-issue-details,
+ .code-issue-comment {
+ border: none;
+ background: transparent;
+ }
+
+ &.highlighted {
+ background: #E4ECF3;
+ }
+}
+
+.code-source .code-issue-modern {
+ margin: 5px 0;
+}
+
+.issue-box-snippet {
+ padding: 3px 0;
+ overflow: hidden;
+ cursor: pointer;
+
+ .code {
+ border: none;
+ }
+}
+
+.issue-box-component {
+ padding: 5px;
+}
+
+.code .issue > pre {
+ display: inline-block;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAGCAYAAAAPDoR2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1M0M2Rjk4M0M3QUYxMUUzODkzRUREMUM5OTNDMjY4QSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1M0M2Rjk4NEM3QUYxMUUzODkzRUREMUM5OTNDMjY4QSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjUzQzZGOTgxQzdBRjExRTM4OTNFREQxQzk5M0MyNjhBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjUzQzZGOTgyQzdBRjExRTM4OTNFREQxQzk5M0MyNjhBIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+bcqJtQAAAEhJREFUeNpi+G+swwDGDAwgbAWlwZiJAQFCgfgwEIfDRaC67ID4NRDnQ2kQnwFZwgFqnANMAQOUYY9sF0wBiCGH5CBkrAgQYACuWi4sSGW8yAAAAABJRU5ErkJggg==);
+ background-repeat: repeat-x;
+ background-size: 4px;
+ background-position: bottom;
+}
overflow: hidden;
}
-.navigator-facets-list-item-option {
- display: inline-block;
- vertical-align: middle;
- line-height: 1;
- margin: 0 6px 6px 6px;
- padding: 4px 5px;
- border: 1px solid @barBorderColor;
- border-radius: 2px;
- background-color: lighten(@barBackgroundColor, 2%);
- font-size: 0;
- font-weight: 300;
- cursor: pointer;
- .trans;
-
- &:hover {
- border: 1px solid @blue;
- text-decoration: none;
- }
-
- &.active {
- border: 1px solid @blue;
- background-color: @lightBlue;
- text-decoration: none;
-
- .navigator-facets-list-item-option-stat {
- border-color: @blue;
- }
- }
-}
-
-.navigator-facets-list-item-option-name {
- font-size: @smallFontSize;
-}
-
-.navigator-facets-list-item-option-stat {
- margin-left: 5px;
- padding-left: 5px;
- border-left: 1px solid @barBorderColor;
- color: @navigatorFacetStatColor;
- font-size: @smallFontSize;
- .trans;
-}
-
// Results
.rulename, .rulename a {
color: #444;
- font-weight: bold;
+ font-weight: 500;
}
.rulename a:hover {
.code-issue {
margin: 0;
font-size: 12px;
- padding: 0 0 10px 0;
.trans(border-color);
.error {
--- /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.
+#
+require 'set'
+
+class Issues2Controller < ApplicationController
+
+ SECTION=Navigation::SECTION_ISSUES2
+
+ before_filter :init_options
+ before_filter :load_fav_filters, :only => [:index, :search, :search2, :filter, :manage, :favourites, :toggle_fav]
+
+ PAGE_SIZE = 100
+
+ # GET /issues/index
+ def index
+ redirect_to :action => 'search'
+ end
+
+ # GET /issues/search
+ def search
+
+ end
+
+ private
+
+ def init_options
+ @options_for_statuses = Internal.issues.listStatus().map { |s| [message('issue.status.' + s), s] }
+ @options_for_resolutions = Internal.issues.listResolutions().map { |s| [message('issue.resolution.' + s), s] }
+ end
+
+ def load_fav_filters
+ @favourite_filters = Internal.issues.findFavouriteIssueFiltersForCurrentUser() if logged_in?
+ end
+
+ def find_filter(id)
+ Internal.issues.findIssueFilter(id)
+ end
+
+ def criteria_params
+ new_params = params.clone
+ new_params.delete('controller')
+ new_params.delete('action')
+ new_params
+ end
+
+ def init_params
+ params['pageSize'] = PAGE_SIZE unless request.xhr?
+ end
+
+ def issues_query_params_sanitized
+ Internal.issues.sanitizeFilterQuery(params).to_hash
+ end
+
+ def issues_query_params_from_filter(filter)
+ Internal.issues.deserializeFilterQuery(filter).to_hash
+ end
+
+end
SECTION_RESOURCE_CONFIGURATION = Navigation.new('resource_configuration', true)
SECTION_SESSION = Navigation.new('session', true)
SECTION_ISSUES = Navigation.new('issues', false)
+ SECTION_ISSUES2 = Navigation.new('issues2', false)
SECTION_MEASURES = Navigation.new('measures', false)
SECTION_QUALITY_PROFILES = Navigation.new('quality_profiles', false)
SECTION_QUALITY_GATES = Navigation.new('quality_gates', false)
<script data-main="<%= ApplicationController.root_context -%>/js/issues/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
<% end %>
-<div class="navigator">
- <div class="navigator-header"></div>
- <div class="navigator-filters"></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-notes"><%= message('issue_filter.max_results_reached', :params => 10000) -%></div>
- <div class="navigator-details"></div>
- </div>
- </div>
+<div class="issues">
+ <i class="spinner"></i>
</div>
-
-
-<script>
- window.SS = {};
-
- _.extend(window.SS, {
- currentUser: '<%= current_user.login if current_user -%>',
- currentUserName: '<%= current_user.name if current_user -%>',
- severities: <%= RulesConfigurationController::RULE_PRIORITIES.to_json.html_safe -%>,
- statuses: <%= @options_for_statuses.to_json.html_safe -%>,
- resolutions: <%= @options_for_resolutions.to_json.html_safe -%>,
- favorites: <%= render :partial => 'issues/filter_favourites' -%>,
- languages: {<% controller.java_facade.getLanguages().to_a.sort {|a,b| a.getName() <=> b.getName()}.each do |language| -%>
- '<%= language.getKey().html_safe -%>': '<%= language.getName().html_safe -%>',
- <% end %>},
-
- phrases: {
- 'actionPlan': '<%= escape_javascript message('issue_filter.criteria.actionPlan') -%>',
- 'actionPlanNotAvailable': '<%= escape_javascript message('issue_filter.criteria.actionPlanNotAvailable') -%>',
- 'any': '<%= escape_javascript message('any') -%>',
- 'anytime': '<%= escape_javascript message('anytime') -%>',
- 'all': '<%= escape_javascript message('all') -%>',
- 'edit': '<%= escape_javascript message('edit') -%>',
- 'delete': '<%= escape_javascript message('delete') -%>',
- 'to': '<%= escape_javascript message('to.downcase') -%>',
- 'project': '<%= escape_javascript message('issue_filter.criteria.project') -%>',
- 'language': '<%= escape_javascript message('language') -%>',
- 'severity': '<%= escape_javascript message('issue_filter.criteria.severity') -%>',
- 'severities': {
- BLOCKER: '<%= escape_javascript message('severity.BLOCKER') -%>',
- CRITICAL: '<%= escape_javascript message('severity.CRITICAL') -%>',
- MAJOR: '<%= escape_javascript message('severity.MAJOR') -%>',
- MINOR: '<%= escape_javascript message('severity.MINOR') -%>',
- INFO: '<%= escape_javascript message('severity.INFO') -%>'
- },
- 'status': '<%= escape_javascript message('issue_filter.criteria.status') -%>',
- 'statuses': {
- OPEN: '<%= escape_javascript message('issue.status.OPEN') -%>',
- CONFIRMED: '<%= escape_javascript message('issue.status.CONFIRMED') -%>',
- REOPENED: '<%= escape_javascript message('issue.status.REOPENED') -%>',
- RESOLVED: '<%= escape_javascript message('issue.status.RESOLVED') -%>',
- CLOSED: '<%= escape_javascript message('issue.status.CLOSED') -%>'
- },
- 'actions': {
- comment: '<%= escape_javascript message('issue.comment.formlink') -%>',
- assign: '<%= escape_javascript message('issue.assign.formlink') -%>',
- assign_to_me: '<%= escape_javascript message('issue.assign.to_me') -%>',
- assigned_to: '<%= escape_javascript message('assigned_to') -%>',
- plan: '<%= escape_javascript message('issue.do_plan') -%>',
- planned_for: '<%= escape_javascript message('issue.planned_for') -%>',
- set_severity: '<%= escape_javascript message('issue.set_severity') -%>',
- <% Internal.issues.listPluginActions().each do |action| -%>
- '<%= escape_javascript action -%>': '<%= escape_javascript message("issue.action.#{action}.formlink") -%>',
- <% end -%>
- },
- 'transitions': {
- confirm: '<%= escape_javascript message('issue.transition.confirm') -%>',
- unconfirm: '<%= escape_javascript message('issue.transition.unconfirm') -%>',
- resolve: '<%= escape_javascript message('issue.transition.resolve') -%>',
- falsepositive: '<%= escape_javascript message('issue.transition.falsepositive') -%>',
- reopen: '<%= escape_javascript message('issue.transition.reopen') -%>',
- close: '<%= escape_javascript message('issue.transition.close') -%>'
- },
- assignee: '<%= escape_javascript message('issue_filter.criteria.assignee') -%>',
- resolution: '<%= escape_javascript message('issue_filter.criteria.resolution') -%>',
- resolutions: {
- 'RESOLVED': '<%= escape_javascript message('issue.status.RESOLVED') -%>',
- 'UNRESOLVED': '<%= escape_javascript message('unresolved') -%>',
- 'FALSE-POSITIVE': '<%= escape_javascript message('issue.resolution.FALSE-POSITIVE') -%>',
- 'FIXED': '<%= escape_javascript message('issue.resolution.FIXED') -%>',
- 'REMOVED': '<%= escape_javascript message('issue.resolution.REMOVED') -%>'
- },
- reporter: '<%= escape_javascript message('issue_filter.criteria.reporter') -%>',
- rule: '<%= escape_javascript message('issue_filter.criteria.rule') -%>',
- created: '<%= escape_javascript message('issue_filter.criteria.created') -%>',
- createdAt: '<%= escape_javascript message('issue_filter.criteria.created_at') -%>',
-
- moreCriteria: '<%= escape_javascript message('issue_filter.more_criteria') -%>',
- unassigned: '<%= escape_javascript message('unassigned') -%>',
- unplanned: '<%= escape_javascript message('issue.unplanned') -%>',
- assignedToMe: '<%= escape_javascript message('assigned_to_me') -%>',
- filtersList: '<%= escape_javascript message('issue_filter.filter_list') -%>',
- commentConfirmDelete: '<%= escape_javascript message('issue.comment.delete_confirm_message') -%>',
- requirementRemoved: '<%= escape_javascript message('issue.technical_debt_deleted') -%>',
-
- select2: {
- noMatches: '<%= escape_javascript message('select2.noMatches') -%>',
- searching: '<%= escape_javascript message('select2.searching') -%>',
- tooShort: '<%= escape_javascript message('select2.tooShort', :params => [2]) -%>'
- },
- 'Done': '<%= escape_javascript message("Done") -%>',
- 'Prev': '<%= escape_javascript message("Prev") -%>',
- 'Next': '<%= escape_javascript message("Next") -%>',
- 'Today': '<%= escape_javascript message("Today") -%>',
- 'January': '<%= escape_javascript message("January") -%>',
- 'February': '<%= escape_javascript message("February") -%>',
- 'March': '<%= escape_javascript message("March") -%>',
- 'April': '<%= escape_javascript message("April") -%>',
- 'May': '<%= escape_javascript message("May") -%>',
- 'June': '<%= escape_javascript message("June") -%>',
- 'July': '<%= escape_javascript message("July") -%>',
- 'August': '<%= escape_javascript message("August") -%>',
- 'September': '<%= escape_javascript message("September") -%>',
- 'October': '<%= escape_javascript message("October") -%>',
- 'November': '<%= escape_javascript message("November") -%>',
- 'December': '<%= escape_javascript message("December") -%>',
- 'Jan': '<%= escape_javascript message("Jan") -%>',
- 'Feb': '<%= escape_javascript message("Feb") -%>',
- 'Mar': '<%= escape_javascript message("Mar") -%>',
- 'Apr': '<%= escape_javascript message("Apr") -%>',
- 'Jun': '<%= escape_javascript message("Jun") -%>',
- 'Jul': '<%= escape_javascript message("Jul") -%>',
- 'Aug': '<%= escape_javascript message("Aug") -%>',
- 'Sep': '<%= escape_javascript message("Sep") -%>',
- 'Oct': '<%= escape_javascript message("Oct") -%>',
- 'Nov': '<%= escape_javascript message("Nov") -%>',
- 'Dec': '<%= escape_javascript message("Dec") -%>',
- 'Sunday': '<%= escape_javascript message("Sunday") -%>',
- 'Monday': '<%= escape_javascript message("Monday") -%>',
- 'Tuesday': '<%= escape_javascript message("Tuesday") -%>',
- 'Wednesday': '<%= escape_javascript message("Wednesday") -%>',
- 'Thursday': '<%= escape_javascript message("Thursday") -%>',
- 'Friday': '<%= escape_javascript message("Friday") -%>',
- 'Saturday': '<%= escape_javascript message("Saturday") -%>',
- 'Sun': '<%= escape_javascript message("Sun") -%>',
- 'Mon': '<%= escape_javascript message("Mon") -%>',
- 'Tue': '<%= escape_javascript message("Tue") -%>',
- 'Wed': '<%= escape_javascript message("Wed") -%>',
- 'Thu': '<%= escape_javascript message("Thu") -%>',
- 'Fri': '<%= escape_javascript message("Fri") -%>',
- 'Sat': '<%= escape_javascript message("Sat") -%>',
- 'Su': '<%= escape_javascript message("Su") -%>',
- 'Mo': '<%= escape_javascript message("Mo") -%>',
- 'Tu': '<%= escape_javascript message("Tu") -%>',
- 'We': '<%= escape_javascript message("We") -%>',
- 'Th': '<%= escape_javascript message("Th") -%>',
- 'Fr': '<%= escape_javascript message("Fr") -%>',
- 'Sa': '<%= escape_javascript message("Sa") -%>'
- }
- });
-
- window.messages = {
- 'all': '<%= escape_javascript message('all') -%>',
- 'assigned_to': '<%= escape_javascript message('assigned_to') -%>',
- 'bulk_change': '<%= escape_javascript message('bulk_change') -%>',
- 'issue.planned_for': '<%= escape_javascript message('issue.planned_for') -%>',
- 'issue.do_plan': '<%= escape_javascript message('issue.do_plan') -%>',
- 'issue.planned_for': '<%= escape_javascript message('issue.planned_for') -%>',
- 'more_actions': '<%= escape_javascript message('more_actions') -%>',
- 'reporter': '<%= escape_javascript message('reporter') -%>',
- 'author': '<%= escape_javascript message('author') -%>',
- 'cancel': '<%= escape_javascript message('cancel') -%>',
- 'save': '<%= escape_javascript message('save') -%>',
- 'issue.technical_debt_short': '<%= escape_javascript message('issue.technical_debt_short') -%>',
- 'issue.technical_debt_deleted': '<%= escape_javascript message('issue.technical_debt_deleted') -%>',
- 'rule': '<%= escape_javascript message('rule') -%>',
- 'changelog': '<%= escape_javascript message('changelog') -%>',
- 'edit': '<%= escape_javascript message('edit') -%>',
- 'delete': '<%= escape_javascript message('delete') -%>',
- 'moreCriteria': '<%= escape_javascript message('issue_filter.more_criteria') -%>',
- 'issue.plan.submit': '<%= escape_javascript message('issue.plan.submit') -%>',
- 'issue.unplan.submit': '<%= escape_javascript message('issue.unplan.submit') -%>',
- 'issue.assign.submit': '<%= escape_javascript message('issue.assign.submit') -%>',
- 'issue.set_severity.submit': '<%= escape_javascript message('issue.set_severity.submit') -%>',
- 'issue.comment.submit': '<%= escape_javascript message('issue.comment.submit') -%>',
- 'issue.plan.error.plan_must_be_created_first_for_admin': '<%= escape_javascript message('issue.plan.error.plan_must_be_created_first_for_admin') -%>',
- 'issue.plan.error.plan_must_be_created_first_for_other': '<%= escape_javascript message('issue.plan.error.plan_must_be_created_first_for_other') -%>',
- 'markdown.helplink': '<%= escape_javascript message('markdown.helplink') -%>',
- 'bold': '<%= escape_javascript message('bold') -%>',
- 'code': '<%= escape_javascript message('code') -%>',
- 'bulleted_point': '<%= escape_javascript message('bulleted_point') -%>',
- 'severity.BLOCKER': '<%= escape_javascript message('severity.BLOCKER') -%>',
- 'severity.CRITICAL': '<%= escape_javascript message('severity.CRITICAL') -%>',
- 'severity.MAJOR': '<%= escape_javascript message('severity.MAJOR') -%>',
- 'severity.MINOR': '<%= escape_javascript message('severity.MINOR') -%>',
- 'severity.INFO': '<%= escape_javascript message('severity.INFO') -%>',
-
- 'component_viewer.measure_section.size': '<%= escape_javascript message('component_viewer.measure_section.size') -%>',
- 'component_viewer.measure_section.complexity': '<%= escape_javascript message('component_viewer.measure_section.complexity') -%>',
- 'component_viewer.measure_section.structure': '<%= escape_javascript message('component_viewer.measure_section.structure') -%>',
- 'component_viewer.measure_section.documentation': '<%= escape_javascript message('component_viewer.measure_section.documentation') -%>',
- 'component_viewer.measure_section.severities': '<%= escape_javascript message('component_viewer.measure_section.severities') -%>',
- 'component_viewer.measure_section.rules': '<%= escape_javascript message('component_viewer.measure_section.rules') -%>',
- 'component_viewer.measure_section.issues': '<%= escape_javascript message('component_viewer.measure_section.issues') -%>',
- 'component_viewer.measure_section.sqale': '<%= escape_javascript message('component_viewer.measure_section.sqale') -%>',
- 'component_viewer.measure_section.unit_tests': '<%= escape_javascript message('component_viewer.measure_section.unit_tests') -%>',
- 'component_viewer.measure_section.integration_tests': '<%= escape_javascript message('component_viewer.measure_section.integration_tests') -%>',
-
- 'component_viewer.issues.current_issue': '<%= escape_javascript message('component_viewer.issues.current_issue') -%>',
- 'component_viewer.issues.unresolved_issues': '<%= escape_javascript message('component_viewer.issues.unresolved_issues') -%>',
- 'component_viewer.issues.false_positive_issues': '<%= escape_javascript message('component_viewer.issues.false_positive_issues') -%>',
-
- 'component_viewer.header.debt': '<%= escape_javascript message('component_viewer.header.debt') -%>',
- 'component_viewer.header.toggle_issues': '<%= escape_javascript message('component_viewer.header.toggle_issues') -%>',
- 'component_viewer.header.toggle_coverage': '<%= escape_javascript message('component_viewer.header.toggle_coverage') -%>',
- 'component_viewer.header.toggle_duplications': '<%= escape_javascript message('component_viewer.header.toggle_duplications') -%>',
-
- 'metric.lines.name': '<%= escape_javascript message('metric.lines.name') -%>',
- 'metric.ncloc.name': '<%= escape_javascript message('metric.ncloc.name') -%>',
- 'metric.complexity.name': '<%= escape_javascript message('metric.complexity.name') -%>',
- 'metric.function_complexity.name': '<%= escape_javascript message('metric.function_complexity.name') -%>',
- 'metric.classes.name': '<%= escape_javascript message('metric.classes.name') -%>',
- 'metric.functions.name': '<%= escape_javascript message('metric.functions.name') -%>',
- 'metric.accessors.name': '<%= escape_javascript message('metric.accessors.name') -%>',
- 'metric.statements.name': '<%= escape_javascript message('metric.statements.name') -%>',
- 'metric.comment_lines.name': '<%= escape_javascript message('metric.comment_lines.name') -%>',
- 'metric.comment_lines_density.name': '<%= escape_javascript message('metric.comment_lines_density.name') -%>',
- 'metric.public_api.name': '<%= escape_javascript message('metric.public_api.name') -%>',
- 'metric.public_undocumented_api.name': '<%= escape_javascript message('metric.public_undocumented_api.name') -%>',
- 'metric.public_documented_api_density.name': '<%= escape_javascript message('metric.public_documented_api_density.name') -%>',
-
- 'metric.coverage.name': '<%= escape_javascript message('metric.coverage.name') -%>',
- 'metric.line_coverage.name': '<%= escape_javascript message('metric.line_coverage.name') -%>',
- 'metric.lines_to_cover.name': '<%= escape_javascript message('metric.lines_to_cover.name') -%>',
- 'metric.covered_lines.name': '<%= escape_javascript message('metric.covered_lines.name') -%>',
- 'metric.uncovered_lines.name': '<%= escape_javascript message('metric.uncovered_lines.name') -%>',
- 'metric.branch_coverage.name': '<%= escape_javascript message('metric.branch_coverage.name') -%>',
- 'metric.conditions_to_cover.name': '<%= escape_javascript message('metric.conditions_to_cover.name') -%>',
- 'metric.covered_conditions.name': '<%= escape_javascript message('metric.covered_conditions.name') -%>',
- 'metric.uncovered_conditions.name': '<%= escape_javascript message('metric.uncovered_conditions.name') -%>',
-
- 'metric.duplicated_blocks.name': '<%= escape_javascript message('metric.duplicated_blocks.name') -%>',
- 'metric.duplicated_files.name': '<%= escape_javascript message('metric.duplicated_files.name') -%>',
- 'metric.duplicated_lines.name': '<%= escape_javascript message('metric.duplicated_lines.name') -%>',
- 'metric.duplicated_lines_density.name': '<%= escape_javascript message('metric.duplicated_lines_density.name') -%>',
-
- 'metric.violations.name': '<%= escape_javascript message('metric.violations.name') -%>',
- 'metric.sqale_index.name': '<%= escape_javascript message('metric.sqale_index.name') -%>',
- 'metric.blocker_violations.name': '<%= escape_javascript message('metric.blocker_violations.name') -%>',
- 'metric.critical_violations.name': '<%= escape_javascript message('metric.critical_violations.name') -%>',
- 'metric.major_violations.name': '<%= escape_javascript message('metric.major_violations.name') -%>',
- 'metric.minor_violations.name': '<%= escape_javascript message('metric.minor_violations.name') -%>',
- 'metric.info_violations.name': '<%= escape_javascript message('metric.info_violations.name') -%>'
- };
-</script>
--- /dev/null
+<%
+ project_uuid = @projectUuids.to_a.first if !@projectUuids.empty? && @projectUuids.to_a.size == 1
+ project_key = Internal.component_api.findByUuid(project_uuid).key() if project_uuid
+ max_page_size_reached = @issues.size >= Internal.issues.maxPageSize()
+
+ transitions_by_issues = {}
+ unresolved_issues = 0
+ unresolved_issues_user_can_admin = 0
+ at_least_one_issue_is_planned = false
+ at_least_one_issue_is_assigned = false
+ all_issues_are_assigned_to_current_user = true
+ @issues.each do |issue|
+ transitions = Internal.issues.listTransitions(issue)
+ transitions.each do |transition|
+ issues_for_transition = transitions_by_issues[transition.key] || 0
+ issues_for_transition += 1
+ transitions_by_issues[transition.key] = issues_for_transition
+ end
+ unresolved_issues += 1 unless issue.resolution()
+ if Java::OrgSonarServerUser::UserSession.get().hasProjectPermissionByUuid('issueadmin', issue.projectUuid)
+ unresolved_issues_user_can_admin += 1 unless issue.resolution()
+ end
+ at_least_one_issue_is_planned ||= issue.actionPlanKey()
+ at_least_one_issue_is_assigned ||= issue.assignee()
+ all_issues_are_assigned_to_current_user &&= issue.assignee() == current_user.login
+ end
+%>
+<form id="bulk-change-form" method="post" action="<%= ApplicationController.root_context -%>/issues/bulk_change">
+ <input type="hidden" name="issues" value="<%= @issues.map { |issue| issue.key() }.join(',') -%>">
+ <input type="hidden" name="actions[]" id="bulk-change-transition-action">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_bulk_change.form.title', {:params => @issues.size.to_s}) -%></h2>
+ </div>
+ <div class="modal-body">
+ <div>
+ <% if max_page_size_reached %>
+ <p class="notes"><%= message('issue_bulk_change.max_issues_reached', :params => @issues.size) -%></p>
+ <% end %>
+ </div>
+ <div class="modal-error"/>
+
+ <% if unresolved_issues > 0 %>
+ <div class="modal-field">
+ <label for="assignee">
+ <%= message('issue.assign.formlink') -%>
+ </label>
+ <input id="assign-action" name="actions[]" type="checkbox" value="assign"/>
+ <%= assign_added_choices = {}
+ # SONAR-4728 Display 'Not assigned' option only if at least one issue is assigned
+ assign_added_choices[''] = escape_javascript(message('unassigned')) if at_least_one_issue_is_assigned
+ # SONAR-4728 Display 'Assign to me' option only if not not all issues are asigned to current user
+ assign_added_choices[current_user.login] = escape_javascript(message('assigned_to_me')) unless all_issues_are_assigned_to_current_user
+ user_select_tag('assign.assignee', :html_id => 'assignee', :open => false, :selected_user => current_user,
+ :include_choices => assign_added_choices)
+ -%>
+ <span style="float:right" class="note">(<%= message('issue_bulk_change.x_issues', :params => unresolved_issues.to_s) -%>)</span>
+ </div>
+ <%
+ if project_key
+ plans = Internal.issues.findOpenActionPlans(project_key)
+ # Display action plan combo box if there are some action plans defined on the project
+ unless plans.empty?
+ first_plan = plans[0]
+ options = plans.map { |plan|
+ label = plan.deadLine ? "#{h plan.name} (#{format_date(plan.deadLine)})" : h(plan.name)
+ [label, plan.key]
+ }
+ # SONAR-4728 Display 'Unplan' option only if at least one issue is planned
+ options.unshift([escape_javascript(message('issue.unplan.submit')), '']) if at_least_one_issue_is_planned
+ plan_options = options_for_select(options, first_plan.key)
+ %>
+ <div class="modal-field">
+ <label for="plan">
+ <%= message('issue.do_plan') -%>
+ </label>
+ <input id="plan-action" name="actions[]" type="checkbox" value="plan"/>
+ <%= dropdown_tag('plan.plan', plan_options, {:show_search_box => false}, {:id => 'plan'}) -%>
+ <span style="float:right" class="note">(<%= message('issue_bulk_change.x_issues', :params => unresolved_issues.to_s) -%>)</span>
+ </div>
+ <% end %>
+ <% end %>
+ <div class="modal-field">
+ <label for="severity">
+ <%= message('issue.set_severity') -%>
+ </label>
+ <input id="set-severity-action" name="actions[]" type="checkbox" value="set_severity"/>
+ <%= severity_dropdown_tag('set_severity.severity', severitiy_select_option_tags, {:show_search_box => false},
+ {:id => 'severity'}) -%>
+ <span style="float:right" class="note">(<%= message('issue_bulk_change.x_issues', :params => unresolved_issues_user_can_admin.to_s) -%>)</span>
+ </div>
+ <% end %>
+
+ <% if transitions_by_issues.size > 0 %>
+ <div class="modal-field">
+ <label>
+ <%= message('issue.transition') -%>
+ </label>
+ <% transitions_by_issues.keys.sort.each do |transition| %>
+ <input type="radio" id="transition-<%= transition -%>" name="do_transition.transition" value="<%= transition -%>"
+ onClick="addTransitionAction();"> <label for="transition-<%= transition -%>" style="float: none; display: inline; left: 0; cursor: pointer;"><%= message("issue.transition.#{transition}") -%></label>
+ <span style="float:right" class="note">(<%= message('issue_bulk_change.x_issues', :params => transitions_by_issues[transition].to_s) %>)</span><br/>
+ <% end %>
+ </div>
+ <% end %>
+
+ <div class="modal-field">
+ <label>
+ <%= message('issue.comment.formlink') -%>
+ <span style="cursor: help;"><%= image_tag 'help.png', :title => h(message('issue_bulk_change.comment.help')) -%></span>
+ </label>
+ <div style="padding: 0 10px 10px 0;">
+ <div>
+ <textarea rows="4" name="comment" id="comment" style="width: 100%"></textarea>
+ </div>
+ <div style="float:right">
+ <%= render :partial => 'markdown/tips' -%>
+ </div>
+ </div>
+ </div>
+
+ <div class="modal-field">
+ <label for="send-notifications">
+ <%= message('issue.send_notifications') -%>
+ </label>
+ <input id="send-notifications" name="sendNotifications" type="checkbox" value="true" />
+ </div>
+ </div>
+ <div class="modal-foot">
+ <span id="bulk-change-loading-image" class="loading-image hidden"><%= image_tag 'loading.gif' %></span>
+ <input type="submit" value="<%= message('apply') -%>" id="bulk-change-submit" class="bulk-change" onclick="return displayLoadingImage()" />
+ <a href="#" onclick="return closeModalWindow()" id="bulk-change-cancel"><%= message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#bulk-change-form").modalForm({
+ success: function () {
+ onBulkIssues(<%= json_escape(params.to_json) -%>);
+ }
+ });
+
+ function addTransitionAction() {
+ $j('#bulk-change-transition-action').val("do_transition");
+ }
+
+ function displayLoadingImage() {
+ $j('#bulk-change-loading-image').removeClass("hidden");
+ }
+
+ function check(id){
+ $j('#'+ id).prop('checked', true);
+ }
+
+ /**
+ * Attach some events on select boxes to automatically select associate check box when selecting an option
+ */
+ $j('#assignee').click(function() { check('assign-action'); });
+ $j('#plan').click(function() { check('plan-action'); });
+ $j('#severity').click(function() { check('set-severity-action'); });
+</script>
--- /dev/null
+<form id="copy-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/copy">
+ <input type="hidden" name="id" value="<%= @filter.id -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.copy_filter') -%></h2>
+ </div>
+ <%= render :partial => 'filter_shared_form' %>
+ <div class="modal-foot">
+ <input type="submit" value="<%= message('copy') -%>" id="copy-submit" class="issue-filter"/>
+ <a href="#" onclick="return closeModalWindow()" id="copy-cancel"><%= h message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#copy-filter-form").modalForm({
+ success: function (data) {
+ return onCopy(data);
+ }
+ });
+</script>
--- /dev/null
+<form id="edit-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/edit">
+ <input type="hidden" name="id" value="<%= @filter.id -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.edit_filter') -%></h2>
+ </div>
+ <%= render :partial => 'filter_shared_form', :locals => {:display_owner => true} %>
+ <div class="modal-foot">
+ <input type="submit" value="<%= message('save') -%>" id="save-submit" class="issue-filter"/>
+ <a href="#" onclick="return closeModalWindow()" id="save-cancel"><%= message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#edit-filter-form").modalForm({
+ success: function (data) {
+ return onEdit(data);
+ }
+ });
+</script>
--- /dev/null
+<% if logged_in? %>
+ {
+ <% @favourite_filters.each do |filter| %>
+ "<%= h filter.id -%>": "<%= escape_javascript filter.name -%>",
+ <% end %>
+ }
+<% else %>
+ null
+<% end %>
--- /dev/null
+<form id="save-as-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/save_as">
+ <input type="hidden" name="data" value="<%= u(@filter_query_serialized) -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.save_filter') -%></h2>
+ </div>
+ <%= render :partial => 'filter_shared_form' %>
+ <div class="modal-foot">
+ <input type="submit" value="<%= message('save') -%>" id="save-as-submit" class="issue-filter"/>
+ <a href="#" onclick="return closeModalWindow()" id="save-as-cancel"><%= message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#save-as-filter-form").modalForm({
+ success: function (data) {
+ return onSaveAs(data);
+ }
+ });
+</script>
--- /dev/null
+<% if !local_assigns.has_key? :display_owner
+ display_owner = false
+ end %>
+<div class="modal-body">
+ <div class="modal-error"/>
+ <div class="modal-field">
+ <label for="name"><%= message('issue_filter.form.name') -%> <em class="mandatory">*</em></label>
+ <input id="name" name="name" type="text" size="50" maxlength="100" value="<%= h(@filter.name) if @filter -%>" autofocus="autofocus"/>
+ </div>
+ <div class="modal-field">
+ <label for="description"><%= message('issue_filter.form.description') -%></label>
+ <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h(@filter.description) if @filter -%>"/>
+ </div>
+ <% if display_owner && can_be_reassigned_by(current_user, @filter) %>
+ <% filter_owner = Api.users.findByLogin(@filter.user) %>
+ <div class="modal-field">
+ <label for="user"><%= h message('issue_filter.form.owner') -%></label>
+ <%= user_select_tag('user', :html_id => 'select-filter-owner', :selected_user => filter_owner) -%>
+ </div>
+ <% else %>
+ <input id="user" name="user" type="hidden" value="<%= h(@filter.user) if @filter -%>"/>
+ <% end %>
+ <% if Internal.issues.canUserShareIssueFilter() %>
+ <div class="modal-field">
+ <% if !@filter || @filter.user.nil? || @filter.user == current_user.login %>
+ <label for="shared"><%= message('issue_filter.form.share') -%></label>
+ <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if (@filter && @filter.shared) -%>/>
+ <% else %>
+ <input id="shared" name="shared" type="hidden" value="<%= @filter.shared if @filter -%>"/>
+ <% end %>
+ </div>
+ <% end %>
+</div>
--- /dev/null
+<%
+ if @issues_result.issues && !@issues_result.issues.empty?
+ colspan = 6
+%>
+ <div id="issues-list">
+ <table class="data width100">
+ <thead>
+ <tr>
+ <th width="1%" nowrap class="column-severity">
+ <%= column_html(@issues_query, @issues_result, message('severity_abbreviated'), message('severity'), 'SEVERITY') %>
+ </th>
+ <th width="1%" nowrap class="column-status">
+ <%= column_html(@issues_query, @issues_result, message('status'), message('status'), 'STATUS') %>
+ </th>
+ <th>
+ <%= message('description') -%>
+ </th>
+ <th nowrap>
+ <%= message('component') -%>
+ </th>
+ <th class="column-assignee">
+ <%= column_html(@issues_query, @issues_result, message('issue_filter.header.assignee'), message('issue_filter.header.assignee'), 'ASSIGNEE') %>
+ </th>
+ <th width="1%" nowrap>
+ <%= message('issue_filter.header.action_plan') -%>
+ </th>
+ <th width="1%" nowrap class="column-update-date">
+ <%= column_html(@issues_query, @issues_result, message('issue_filter.header.update_date'), message('issue_filter.header.update_date'), 'UPDATE_DATE') %>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <%
+ @issues_result.issues.each do |issue|
+ %>
+ <tr class="<%= cycle('even', 'odd') -%>">
+ <td width="1%" nowrap>
+ <i class="icon-severity-<%= issue.severity.downcase -%>"></i>
+ </td>
+ <td>
+ <%= message("issue.status.#{issue.status}") -%>
+ <% if issue.resolution %>
+ <span class="note" style="white-space: nowrap">[<%= message("issue.resolution.#{issue.resolution}") -%>]</span>
+ <% end %>
+ </td>
+ <td>
+ <a class='open-modal rule-modal issue-detail-link' modal-width='900' href='<%= url_for :controller => 'issue', :action => 'show', :id => issue.key, :modal => true -%>'>
+ <%= h truncate(issue.message, :length => 100) -%></a>
+ </td>
+ <td>
+ <% project = @issues_result.project(issue)
+ component = @issues_result.component(issue) -%>
+ <div class="subtitle"><%= h (truncate(project.name, :length => 100)) -%></div>
+ <% if component %>
+ <!-- Do not display component name when issue is on module -->
+ <% if component.key != project.key %>
+ <%= h component.longName() -%>
+ <% end %>
+ <% else %>
+ <del><%= h issue.componentKey() %></del>
+ <% end %>
+ </td>
+ <td>
+ <%= h @issues_result.user(issue.assignee).name if issue.assignee -%>
+ </td>
+ <td>
+ <%= h @issues_result.actionPlan(issue).name if issue.actionPlanKey() -%>
+ </td>
+ <td width="1%" nowrap>
+ <%= human_short_date(Api::Utils.java_to_ruby_datetime(issue.updateDate())) -%>
+ </td>
+ </tr>
+ <%
+ end
+ %>
+ </tbody>
+ <%= if @ajax_mode
+ paginate_java(@issues_result.paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true,
+ :url_results => url_for({:controller => 'issues', :action => 'search'}.merge(params))) { |label, page_id|
+ link_to_function label, "refreshList('#{@issues_query.sort}', #{@issues_query.asc}, #{page_id})"
+ }
+ else
+ paginate_java(@issues_result.paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id|
+ link_to(label, params.merge({:pageIndex => page_id}))
+ }
+ end
+ %>
+ </table>
+ </div>
+<%
+ end
+%>
+
+<script type="text/javascript">
+ var filterCriteria = <%= json_escape(@issues_query_params.to_json) -%>;
+
+ function refreshList(sort, asc, page) {
+ $j('#issue-filter-foot_pages').hide();
+ $j('#issue-filter-foot_loading').show();
+
+ filterCriteria['sort']=sort;
+ filterCriteria['asc']=asc;
+ filterCriteria['pageIndex']=page;
+ var url = baseUrl + '/issues/search?' + $j.param(filterCriteria);
+
+ <% if @ajax_mode %>
+ $j('.issues-content').load(url, function () {
+ // As issues will be loaded after open-modal has been processed by jQuery, we have to process manually modal classes
+ processModal();
+ });
+ <% else %>
+ window.location = url;
+ <% end %>
+ return false;
+ }
+
+ function processModal(){
+ $j('.issues-content .open-modal').modal();
+ }
+
+ <% if @ajax_mode %>
+ $j(document).ready(function() {
+ processModal();
+ });
+ <% end %>
+</script>
--- /dev/null
+<% if @issues_result && @issues_result.maxResultsReached() %>
+ <p class="notes"><%= message('issue_filter.max_results_reached', :params => @issues_result.paging.total()) -%></p>
+<% end %>
+
+<% unless @issues_result.issues && !@issues_result.issues.empty? %>
+ <p class="notes" style="padding: 5px;"><%= message('issue_filter.no_result') -%></p>
+<% end %>
+
+<% if logged_in? && !@first_search %>
+ <div id="issue-filters-operations" class="line-block marginbottom10">
+ <ul class="operations">
+ <% if @filter && @filter.id %>
+ <li><a id="copy" href="<%= url_for :action => 'copy_form', :id => @filter.id -%>" class="link-action open-modal"><%= message('copy') -%></a></li>
+ <% end %>
+ <% if !@unchanged && @filter && @filter.id && @filter.user == current_user.login %>
+ <li>
+ <%= link_to message('save'), params.merge({:action => 'save', :id => @filter.id}), :class => 'link-action', :id => 'save', :method => :post -%>
+ </li>
+ <% end %>
+ <% unless @filter %>
+ <li>
+ <a id="save-as" href="<%= url_for params.merge({:action => 'save_as_form'}) -%>" class="link-action open-modal"><%= message('save_as') -%></a>
+ </li>
+ <% end %>
+ <% if @issues_result.issues && !@issues_result.issues.empty? %>
+ <li class="last">
+ <a id="bulk-change" href="<%= url_for params.merge({:action => 'bulk_change_form'}) -%>"
+ class="link-action open-modal"><%= message('bulk_change') -%></a>
+ </li>
+ <% end %>
+ </ul>
+
+ <% if @filter && @filter.id && @filter.name.present? %>
+ <div class="page_title" id="filter-title">
+ <p>
+ <span class="h3"><%= h @filter.name -%></span>
+ <span class="note">
+ <% if !@filter.shared %>
+ [<%= message 'issue_filter.private' -%>]
+ <% elsif @filter.user==current_user.login %>
+ [<%= message 'issue_filter.shared_with_all_users' -%>]
+ <% elsif @filter.user %>
+ [<%= message 'shared_by' -%> <%= Api.users.findByLogin(@filter.user).name -%>]
+ <% end %>
+ </span>
+ <% if @filter.user == current_user.login %>
+ <a href="<%= url_for :action => 'edit_form', :id => @filter.id -%>" class="open-modal" id="edit-filter"><%= image_tag 'pencil-small.png', :alt => message('edit') -%></a>
+ <% end %>
+ </p>
+ </div>
+ <% end %>
+ </div>
+<% end %>
--- /dev/null
+<% if logged_in? && @issues_result.issues && !@issues_result.issues.empty? %>
+ <div class="line-block marginbottom10">
+ <div id="issue-filters-operations" style="padding-right: 5px; padding-top: 5px;">
+ <ul class="operations">
+ <li class="last">
+ <a id="bulk-change" href="<%= url_for params.merge({:controller => 'issues', :action => 'bulk_change_form'}) -%>"
+ class="link-action open-modal"><%= message('bulk_change') -%></a>
+ </li>
+ </ul>
+ </div>
+ </div>
+<% end %>
--- /dev/null
+<div class="issues-content">
+ <%= render :partial => 'operations' -%>
+ <%= render :partial => 'list' -%>
+</div>
--- /dev/null
+<div class="issues-content">
+ <%
+ if @issues_result.issues && !@issues_result.issues.empty?
+ %>
+ <%= render :partial => 'operations_ajax' -%>
+ <%= render :partial => 'list' -%>
+ <% else %>
+ <%= render :partial => 'shared/no_issues' -%>
+ <% end %>
+</div>
--- /dev/null
+<% content_for :script do %>
+ <script>
+ $j(document).ready(function () {
+ $j(".issue-filter-star").click(function () {
+ var filterId = $j(this).attr('filter-id');
+ var star = $j(this);
+ $j.ajax({
+ type: 'POST',
+ url: baseUrl + "/issues/toggle_fav",
+ data: {id: filterId},
+ success: function (data) {
+ if (data == 'true') {
+ star.removeClass('icon-not-favorite').addClass('icon-favorite');
+ star.attr('title', '<%= escape_javascript message('click_to_remove_from_favorites') -%>');
+ } else {
+ star.removeClass('icon-favorite').addClass('icon-not-favorite');
+ star.attr('title', '<%= escape_javascript message('click_to_add_to_favorites') -%>');
+ }
+ $j('#sidebar-favourites').load(baseUrl + '/issues/favourites');
+ }
+ });
+ });
+ });
+
+ function onSaveAs(data) {
+ window.location = baseUrl + '/issues/search#id=' + data;
+ }
+
+ function onCopy(data) {
+ window.location = baseUrl + '/issues/search#id=' + data;
+ }
+
+ function onEdit(data) {
+ window.location = baseUrl + '/issues/search#id=' + data;
+ }
+ </script>
+<% end %>
+<div>
+ <div class="page">
+ <h1><%= message 'issue_filter.manage.my_filters' -%></h1>
+ <table class="data marginbottom10" id="my-issue-filters">
+ <thead>
+ <tr>
+ <th class="thin"></th>
+ <th><%= message('issue_filter.form.name') -%></th>
+ <th><%= message('issue_filter.sharing') -%></th>
+ <th class="right"><%= message('operations') -%></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% if @filters.empty? %>
+ <tr class="even">
+ <td colspan="4"><%= message('issue_filter.no_filters') -%></td>
+ </tr>
+ <% else %>
+ <% @filters.each do |filter| %>
+ <tr id="my-issue-filter-<%= filter.name.parameterize -%>" class="<%= cycle('even', 'odd', :name => 'my-filters') -%>">
+ <td>
+ <%= issue_filter_star(filter, @favourite_filter_ids.include?(filter.id)) -%>
+ </td>
+ <td>
+ <a href="<%= ApplicationController.root_context -%>/issues/search#id=<%= h filter.id -%>|<%= h filter.data -%>"><%= h filter.name -%></a>
+ <% if filter.description %>
+ <div class="note"><%= h filter.description -%></div>
+ <% end %>
+ </td>
+ <td>
+ <% if filter.shared %>
+ <%= message 'issue_filter.shared_with_all_users' -%>
+ <% else %>
+ <%= message 'issue_filter.private' -%>
+ <% end %>
+ </td>
+ <td class="thin nowrap right">
+ <a id="copy-<%= filter.name.parameterize -%>" href="<%= ApplicationController.root_context -%>/issues/copy_form/<%= filter.id -%>"
+ class="link-action open-modal"><%= message('copy') -%></a>
+
+ <a id="edit_<%= filter.name.parameterize -%>" href="<%= ApplicationController.root_context -%>/issues/edit_form/<%= filter.id -%>"
+ class="link-action open-modal"><%= message('edit') -%></a>
+
+ <%= link_to_action message('delete'), "#{ApplicationController.root_context}/issues/delete/#{filter.id}",
+ :class => 'link-action link-red',
+ :id => "delete_#{filter.name.parameterize}",
+ :confirm_button => message('delete'),
+ :confirm_title => 'issue_filter.delete_confirm_title',
+ :confirm_msg => 'issue_filter.are_you_sure_want_delete_filter_x',
+ :confirm_msg_params => [filter.name] -%>
+ </td>
+ </tr>
+ <% end %>
+ <% end %>
+ </tbody>
+ </table>
+
+ <br/>
+
+ <h1><%= message 'issue_filter.manage.shared_filters' -%></h1>
+ <table class="data" id="shared-filters">
+ <thead>
+ <tr>
+ <th class="thin"></th>
+ <th><%= message('issue_filter.form.name') -%></th>
+ <th><%= message('shared_by') -%></th>
+ <th class="right"><%= message('operations') -%></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% if @shared_filters.empty? %>
+ <tr class="even">
+ <td colspan="4"><%= message('issue_filter.no_filters') -%></td>
+ </tr>
+ <% else %>
+ <% @shared_filters.each do |filter| %>
+ <tr id="shared-<%= filter.name.parameterize -%>" class="<%= cycle('even', 'odd', :name => 'shared-filters') -%>">
+ <td>
+ <%= issue_filter_star(filter, @favourite_filter_ids.include?(filter.id)) -%>
+ </td>
+ <td>
+ <a href="<%= ApplicationController.root_context -%>/issues/search#id=<%= h filter.id -%>|<%= h filter.data -%>"><%= h filter.name -%></a>
+ <% if filter.description %>
+ <div class="note"><%= h filter.description -%></div>
+ <% end %>
+ </td>
+ <td>
+ <%= h Api.users.findByLogin(filter.user).name -%>
+ </td>
+ <td class="thin nowrap right">
+ <a id="copy-<%= filter.name.parameterize -%>" href="<%= ApplicationController.root_context -%>/issues/copy_form/<%= filter.id -%>" class="link-action open-modal"><%= message('copy') -%></a>
+ <% if has_role?(:admin) %>
+
+ <a id="edit_shared_<%= filter.name.parameterize -%>" href="<%= ApplicationController.root_context -%>/issues/edit_form/<%= filter.id -%>" class="link-action open-modal"><%= message('edit') -%></a>
+
+ <%= link_to_action message('delete'), "#{ApplicationController.root_context}/issues/delete/#{filter.id}",
+ :class => 'link-action link-red',
+ :id => "delete_system_#{filter.name.parameterize}",
+ :confirm_button => message('delete'),
+ :confirm_title => 'issue_filter.delete_confirm_title',
+ :confirm_msg => 'issue_filter.are_you_sure_want_delete_filter_x',
+ :confirm_msg_params => [filter.name] -%>
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+ <% end %>
+ </tbody>
+ </table>
+
+ </div>
+</div>
--- /dev/null
+<% content_for :script do %>
+ <script data-main="<%= ApplicationController.root_context -%>/js/issues-old/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
+<% end %>
+
+<div class="navigator">
+ <div class="navigator-header"></div>
+ <div class="navigator-filters"></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-notes"><%= message('issue_filter.max_results_reached', :params => 10000) -%></div>
+ <div class="navigator-details"></div>
+ </div>
+ </div>
+</div>
+
+
+<script>
+ window.SS = {};
+
+ _.extend(window.SS, {
+ currentUser: '<%= current_user.login if current_user -%>',
+ currentUserName: '<%= current_user.name if current_user -%>',
+ severities: <%= RulesConfigurationController::RULE_PRIORITIES.to_json.html_safe -%>,
+ statuses: <%= @options_for_statuses.to_json.html_safe -%>,
+ resolutions: <%= @options_for_resolutions.to_json.html_safe -%>,
+ favorites: <%= render :partial => 'issues/filter_favourites' -%>,
+ languages: {<% controller.java_facade.getLanguages().to_a.sort {|a,b| a.getName() <=> b.getName()}.each do |language| -%>
+ '<%= language.getKey().html_safe -%>': '<%= language.getName().html_safe -%>',
+ <% end %>},
+
+ phrases: {
+ 'actionPlan': '<%= escape_javascript message('issue_filter.criteria.actionPlan') -%>',
+ 'actionPlanNotAvailable': '<%= escape_javascript message('issue_filter.criteria.actionPlanNotAvailable') -%>',
+ 'any': '<%= escape_javascript message('any') -%>',
+ 'anytime': '<%= escape_javascript message('anytime') -%>',
+ 'all': '<%= escape_javascript message('all') -%>',
+ 'edit': '<%= escape_javascript message('edit') -%>',
+ 'delete': '<%= escape_javascript message('delete') -%>',
+ 'to': '<%= escape_javascript message('to.downcase') -%>',
+ 'project': '<%= escape_javascript message('issue_filter.criteria.project') -%>',
+ 'language': '<%= escape_javascript message('language') -%>',
+ 'severity': '<%= escape_javascript message('issue_filter.criteria.severity') -%>',
+ 'severities': {
+ BLOCKER: '<%= escape_javascript message('severity.BLOCKER') -%>',
+ CRITICAL: '<%= escape_javascript message('severity.CRITICAL') -%>',
+ MAJOR: '<%= escape_javascript message('severity.MAJOR') -%>',
+ MINOR: '<%= escape_javascript message('severity.MINOR') -%>',
+ INFO: '<%= escape_javascript message('severity.INFO') -%>'
+ },
+ 'status': '<%= escape_javascript message('issue_filter.criteria.status') -%>',
+ 'statuses': {
+ OPEN: '<%= escape_javascript message('issue.status.OPEN') -%>',
+ CONFIRMED: '<%= escape_javascript message('issue.status.CONFIRMED') -%>',
+ REOPENED: '<%= escape_javascript message('issue.status.REOPENED') -%>',
+ RESOLVED: '<%= escape_javascript message('issue.status.RESOLVED') -%>',
+ CLOSED: '<%= escape_javascript message('issue.status.CLOSED') -%>'
+ },
+ 'actions': {
+ comment: '<%= escape_javascript message('issue.comment.formlink') -%>',
+ assign: '<%= escape_javascript message('issue.assign.formlink') -%>',
+ assign_to_me: '<%= escape_javascript message('issue.assign.to_me') -%>',
+ assigned_to: '<%= escape_javascript message('assigned_to') -%>',
+ plan: '<%= escape_javascript message('issue.do_plan') -%>',
+ planned_for: '<%= escape_javascript message('issue.planned_for') -%>',
+ set_severity: '<%= escape_javascript message('issue.set_severity') -%>',
+ <% Internal.issues.listPluginActions().each do |action| -%>
+ '<%= escape_javascript action -%>': '<%= escape_javascript message("issue.action.#{action}.formlink") -%>',
+ <% end -%>
+ },
+ 'transitions': {
+ confirm: '<%= escape_javascript message('issue.transition.confirm') -%>',
+ unconfirm: '<%= escape_javascript message('issue.transition.unconfirm') -%>',
+ resolve: '<%= escape_javascript message('issue.transition.resolve') -%>',
+ falsepositive: '<%= escape_javascript message('issue.transition.falsepositive') -%>',
+ reopen: '<%= escape_javascript message('issue.transition.reopen') -%>',
+ close: '<%= escape_javascript message('issue.transition.close') -%>'
+ },
+ assignee: '<%= escape_javascript message('issue_filter.criteria.assignee') -%>',
+ resolution: '<%= escape_javascript message('issue_filter.criteria.resolution') -%>',
+ resolutions: {
+ 'RESOLVED': '<%= escape_javascript message('issue.status.RESOLVED') -%>',
+ 'UNRESOLVED': '<%= escape_javascript message('unresolved') -%>',
+ 'FALSE-POSITIVE': '<%= escape_javascript message('issue.resolution.FALSE-POSITIVE') -%>',
+ 'FIXED': '<%= escape_javascript message('issue.resolution.FIXED') -%>',
+ 'REMOVED': '<%= escape_javascript message('issue.resolution.REMOVED') -%>'
+ },
+ reporter: '<%= escape_javascript message('issue_filter.criteria.reporter') -%>',
+ rule: '<%= escape_javascript message('issue_filter.criteria.rule') -%>',
+ created: '<%= escape_javascript message('issue_filter.criteria.created') -%>',
+ createdAt: '<%= escape_javascript message('issue_filter.criteria.created_at') -%>',
+
+ moreCriteria: '<%= escape_javascript message('issue_filter.more_criteria') -%>',
+ unassigned: '<%= escape_javascript message('unassigned') -%>',
+ unplanned: '<%= escape_javascript message('issue.unplanned') -%>',
+ assignedToMe: '<%= escape_javascript message('assigned_to_me') -%>',
+ filtersList: '<%= escape_javascript message('issue_filter.filter_list') -%>',
+ commentConfirmDelete: '<%= escape_javascript message('issue.comment.delete_confirm_message') -%>',
+ requirementRemoved: '<%= escape_javascript message('issue.technical_debt_deleted') -%>',
+
+ select2: {
+ noMatches: '<%= escape_javascript message('select2.noMatches') -%>',
+ searching: '<%= escape_javascript message('select2.searching') -%>',
+ tooShort: '<%= escape_javascript message('select2.tooShort', :params => [2]) -%>'
+ },
+ 'Done': '<%= escape_javascript message("Done") -%>',
+ 'Prev': '<%= escape_javascript message("Prev") -%>',
+ 'Next': '<%= escape_javascript message("Next") -%>',
+ 'Today': '<%= escape_javascript message("Today") -%>',
+ 'January': '<%= escape_javascript message("January") -%>',
+ 'February': '<%= escape_javascript message("February") -%>',
+ 'March': '<%= escape_javascript message("March") -%>',
+ 'April': '<%= escape_javascript message("April") -%>',
+ 'May': '<%= escape_javascript message("May") -%>',
+ 'June': '<%= escape_javascript message("June") -%>',
+ 'July': '<%= escape_javascript message("July") -%>',
+ 'August': '<%= escape_javascript message("August") -%>',
+ 'September': '<%= escape_javascript message("September") -%>',
+ 'October': '<%= escape_javascript message("October") -%>',
+ 'November': '<%= escape_javascript message("November") -%>',
+ 'December': '<%= escape_javascript message("December") -%>',
+ 'Jan': '<%= escape_javascript message("Jan") -%>',
+ 'Feb': '<%= escape_javascript message("Feb") -%>',
+ 'Mar': '<%= escape_javascript message("Mar") -%>',
+ 'Apr': '<%= escape_javascript message("Apr") -%>',
+ 'Jun': '<%= escape_javascript message("Jun") -%>',
+ 'Jul': '<%= escape_javascript message("Jul") -%>',
+ 'Aug': '<%= escape_javascript message("Aug") -%>',
+ 'Sep': '<%= escape_javascript message("Sep") -%>',
+ 'Oct': '<%= escape_javascript message("Oct") -%>',
+ 'Nov': '<%= escape_javascript message("Nov") -%>',
+ 'Dec': '<%= escape_javascript message("Dec") -%>',
+ 'Sunday': '<%= escape_javascript message("Sunday") -%>',
+ 'Monday': '<%= escape_javascript message("Monday") -%>',
+ 'Tuesday': '<%= escape_javascript message("Tuesday") -%>',
+ 'Wednesday': '<%= escape_javascript message("Wednesday") -%>',
+ 'Thursday': '<%= escape_javascript message("Thursday") -%>',
+ 'Friday': '<%= escape_javascript message("Friday") -%>',
+ 'Saturday': '<%= escape_javascript message("Saturday") -%>',
+ 'Sun': '<%= escape_javascript message("Sun") -%>',
+ 'Mon': '<%= escape_javascript message("Mon") -%>',
+ 'Tue': '<%= escape_javascript message("Tue") -%>',
+ 'Wed': '<%= escape_javascript message("Wed") -%>',
+ 'Thu': '<%= escape_javascript message("Thu") -%>',
+ 'Fri': '<%= escape_javascript message("Fri") -%>',
+ 'Sat': '<%= escape_javascript message("Sat") -%>',
+ 'Su': '<%= escape_javascript message("Su") -%>',
+ 'Mo': '<%= escape_javascript message("Mo") -%>',
+ 'Tu': '<%= escape_javascript message("Tu") -%>',
+ 'We': '<%= escape_javascript message("We") -%>',
+ 'Th': '<%= escape_javascript message("Th") -%>',
+ 'Fr': '<%= escape_javascript message("Fr") -%>',
+ 'Sa': '<%= escape_javascript message("Sa") -%>'
+ }
+ });
+
+ window.messages = {
+ 'all': '<%= escape_javascript message('all') -%>',
+ 'assigned_to': '<%= escape_javascript message('assigned_to') -%>',
+ 'bulk_change': '<%= escape_javascript message('bulk_change') -%>',
+ 'issue.planned_for': '<%= escape_javascript message('issue.planned_for') -%>',
+ 'issue.do_plan': '<%= escape_javascript message('issue.do_plan') -%>',
+ 'issue.planned_for': '<%= escape_javascript message('issue.planned_for') -%>',
+ 'more_actions': '<%= escape_javascript message('more_actions') -%>',
+ 'reporter': '<%= escape_javascript message('reporter') -%>',
+ 'author': '<%= escape_javascript message('author') -%>',
+ 'cancel': '<%= escape_javascript message('cancel') -%>',
+ 'save': '<%= escape_javascript message('save') -%>',
+ 'issue.technical_debt_short': '<%= escape_javascript message('issue.technical_debt_short') -%>',
+ 'issue.technical_debt_deleted': '<%= escape_javascript message('issue.technical_debt_deleted') -%>',
+ 'rule': '<%= escape_javascript message('rule') -%>',
+ 'changelog': '<%= escape_javascript message('changelog') -%>',
+ 'edit': '<%= escape_javascript message('edit') -%>',
+ 'delete': '<%= escape_javascript message('delete') -%>',
+ 'moreCriteria': '<%= escape_javascript message('issue_filter.more_criteria') -%>',
+ 'issue.plan.submit': '<%= escape_javascript message('issue.plan.submit') -%>',
+ 'issue.unplan.submit': '<%= escape_javascript message('issue.unplan.submit') -%>',
+ 'issue.assign.submit': '<%= escape_javascript message('issue.assign.submit') -%>',
+ 'issue.set_severity.submit': '<%= escape_javascript message('issue.set_severity.submit') -%>',
+ 'issue.comment.submit': '<%= escape_javascript message('issue.comment.submit') -%>',
+ 'issue.plan.error.plan_must_be_created_first_for_admin': '<%= escape_javascript message('issue.plan.error.plan_must_be_created_first_for_admin') -%>',
+ 'issue.plan.error.plan_must_be_created_first_for_other': '<%= escape_javascript message('issue.plan.error.plan_must_be_created_first_for_other') -%>',
+ 'markdown.helplink': '<%= escape_javascript message('markdown.helplink') -%>',
+ 'bold': '<%= escape_javascript message('bold') -%>',
+ 'code': '<%= escape_javascript message('code') -%>',
+ 'bulleted_point': '<%= escape_javascript message('bulleted_point') -%>',
+ 'severity.BLOCKER': '<%= escape_javascript message('severity.BLOCKER') -%>',
+ 'severity.CRITICAL': '<%= escape_javascript message('severity.CRITICAL') -%>',
+ 'severity.MAJOR': '<%= escape_javascript message('severity.MAJOR') -%>',
+ 'severity.MINOR': '<%= escape_javascript message('severity.MINOR') -%>',
+ 'severity.INFO': '<%= escape_javascript message('severity.INFO') -%>',
+
+ 'component_viewer.measure_section.size': '<%= escape_javascript message('component_viewer.measure_section.size') -%>',
+ 'component_viewer.measure_section.complexity': '<%= escape_javascript message('component_viewer.measure_section.complexity') -%>',
+ 'component_viewer.measure_section.structure': '<%= escape_javascript message('component_viewer.measure_section.structure') -%>',
+ 'component_viewer.measure_section.documentation': '<%= escape_javascript message('component_viewer.measure_section.documentation') -%>',
+ 'component_viewer.measure_section.severities': '<%= escape_javascript message('component_viewer.measure_section.severities') -%>',
+ 'component_viewer.measure_section.rules': '<%= escape_javascript message('component_viewer.measure_section.rules') -%>',
+ 'component_viewer.measure_section.issues': '<%= escape_javascript message('component_viewer.measure_section.issues') -%>',
+ 'component_viewer.measure_section.sqale': '<%= escape_javascript message('component_viewer.measure_section.sqale') -%>',
+ 'component_viewer.measure_section.unit_tests': '<%= escape_javascript message('component_viewer.measure_section.unit_tests') -%>',
+ 'component_viewer.measure_section.integration_tests': '<%= escape_javascript message('component_viewer.measure_section.integration_tests') -%>',
+
+ 'component_viewer.issues.current_issue': '<%= escape_javascript message('component_viewer.issues.current_issue') -%>',
+ 'component_viewer.issues.unresolved_issues': '<%= escape_javascript message('component_viewer.issues.unresolved_issues') -%>',
+ 'component_viewer.issues.false_positive_issues': '<%= escape_javascript message('component_viewer.issues.false_positive_issues') -%>',
+
+ 'component_viewer.header.debt': '<%= escape_javascript message('component_viewer.header.debt') -%>',
+ 'component_viewer.header.toggle_issues': '<%= escape_javascript message('component_viewer.header.toggle_issues') -%>',
+ 'component_viewer.header.toggle_coverage': '<%= escape_javascript message('component_viewer.header.toggle_coverage') -%>',
+ 'component_viewer.header.toggle_duplications': '<%= escape_javascript message('component_viewer.header.toggle_duplications') -%>',
+
+ 'metric.lines.name': '<%= escape_javascript message('metric.lines.name') -%>',
+ 'metric.ncloc.name': '<%= escape_javascript message('metric.ncloc.name') -%>',
+ 'metric.complexity.name': '<%= escape_javascript message('metric.complexity.name') -%>',
+ 'metric.function_complexity.name': '<%= escape_javascript message('metric.function_complexity.name') -%>',
+ 'metric.classes.name': '<%= escape_javascript message('metric.classes.name') -%>',
+ 'metric.functions.name': '<%= escape_javascript message('metric.functions.name') -%>',
+ 'metric.accessors.name': '<%= escape_javascript message('metric.accessors.name') -%>',
+ 'metric.statements.name': '<%= escape_javascript message('metric.statements.name') -%>',
+ 'metric.comment_lines.name': '<%= escape_javascript message('metric.comment_lines.name') -%>',
+ 'metric.comment_lines_density.name': '<%= escape_javascript message('metric.comment_lines_density.name') -%>',
+ 'metric.public_api.name': '<%= escape_javascript message('metric.public_api.name') -%>',
+ 'metric.public_undocumented_api.name': '<%= escape_javascript message('metric.public_undocumented_api.name') -%>',
+ 'metric.public_documented_api_density.name': '<%= escape_javascript message('metric.public_documented_api_density.name') -%>',
+
+ 'metric.coverage.name': '<%= escape_javascript message('metric.coverage.name') -%>',
+ 'metric.line_coverage.name': '<%= escape_javascript message('metric.line_coverage.name') -%>',
+ 'metric.lines_to_cover.name': '<%= escape_javascript message('metric.lines_to_cover.name') -%>',
+ 'metric.covered_lines.name': '<%= escape_javascript message('metric.covered_lines.name') -%>',
+ 'metric.uncovered_lines.name': '<%= escape_javascript message('metric.uncovered_lines.name') -%>',
+ 'metric.branch_coverage.name': '<%= escape_javascript message('metric.branch_coverage.name') -%>',
+ 'metric.conditions_to_cover.name': '<%= escape_javascript message('metric.conditions_to_cover.name') -%>',
+ 'metric.covered_conditions.name': '<%= escape_javascript message('metric.covered_conditions.name') -%>',
+ 'metric.uncovered_conditions.name': '<%= escape_javascript message('metric.uncovered_conditions.name') -%>',
+
+ 'metric.duplicated_blocks.name': '<%= escape_javascript message('metric.duplicated_blocks.name') -%>',
+ 'metric.duplicated_files.name': '<%= escape_javascript message('metric.duplicated_files.name') -%>',
+ 'metric.duplicated_lines.name': '<%= escape_javascript message('metric.duplicated_lines.name') -%>',
+ 'metric.duplicated_lines_density.name': '<%= escape_javascript message('metric.duplicated_lines_density.name') -%>',
+
+ 'metric.violations.name': '<%= escape_javascript message('metric.violations.name') -%>',
+ 'metric.sqale_index.name': '<%= escape_javascript message('metric.sqale_index.name') -%>',
+ 'metric.blocker_violations.name': '<%= escape_javascript message('metric.blocker_violations.name') -%>',
+ 'metric.critical_violations.name': '<%= escape_javascript message('metric.critical_violations.name') -%>',
+ 'metric.major_violations.name': '<%= escape_javascript message('metric.major_violations.name') -%>',
+ 'metric.minor_violations.name': '<%= escape_javascript message('metric.minor_violations.name') -%>',
+ 'metric.info_violations.name': '<%= escape_javascript message('metric.info_violations.name') -%>'
+ };
+</script>
<li>
<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 -%>/issues2/index" class="<%= 'selected' if selected_section==Navigation::SECTION_ISSUES2 -%>">Old Issues</a>
+ </li>
<li>
<a href="<%= ApplicationController.root_context -%>/coding_rules" class="<%= 'selected' if selected_section==Navigation::SECTION_CODING_RULES -%>"><%= message('coding_rules.page') -%></a>
</li>
issues.found=Found
+#------------------------------------------------------------------------------
+#
+# ISSUES FACETS
+#
+#------------------------------------------------------------------------------
+issues.facet.severities=Severity
+issues.facet.componentRootUuids=Project
+issues.facet.statuses=Status
+issues.facet.actionPlans=Action Plan
+issues.facet.assignees=Assignee
+issues.facet.components=Component
+issues.facet.rules=Rule
+issues.facet.resolutions=Resolution
+issues.facet.languages=Language
+
+
#------------------------------------------------------------------------------
#
# ISSUE BULK CHANGE