'component-viewer/header/duplications-header'
'component-viewer/header/tests-header'
- 'component-viewer/time-changes-popup'
-
'common/handlebars-extensions'
], (
Marionette
CoverageHeaderView
DuplicationsHeaderView
TestsHeaderView
-
- TimeChangesPopupView
) ->
$ = jQuery
'click .js-toggle-duplications': 'toggleDuplications'
'click .js-toggle-scm': 'toggleSCM'
- 'click .component-viewer-header-time-changes a': 'showTimeChangesPopup'
-
initialize: (options) ->
options.main.settings.on 'change', => @changeSettings()
onRender: ->
@delegateEvents()
+ activeHeaderTab = @state.get 'activeHeaderTab'
+ activeHeaderItem = @state.get 'activeHeaderItem'
+ if activeHeaderTab
+ @enableBar(activeHeaderTab).done =>
+ if activeHeaderItem
+ @enableBarItem activeHeaderItem
toggleFavorite: ->
@state.set 'activeHeaderTab', scope
bar = _.findWhere BARS, scope: scope
@barRegion.show new bar.view
- state: @state, component: @component, settings: @settings, source: @model, header: @
+ main: @options.main, state: @state, component: @component, settings: @settings, source: @model, header: @
@ui.expandLinks.filter("[data-scope=#{scope}]").addClass 'active'
+ enableBarItem: (item) ->
+ @$(item).click()
+
+
showExpandedBar: (e) ->
el = $(e.currentTarget)
active = el.is '.active'
toggleWorkspace: (e) -> @toggleSetting e, @options.main.showWorkspace, @options.main.hideWorkspace
- showTimeChangesPopup: (e) ->
- e.stopPropagation()
- $('body').click()
- popup = new TimeChangesPopupView
- triggerEl: $(e.currentTarget)
- main: @options.main
- popup.render()
+ showTimeChangesSpinner: ->
+ @$('.component-viewer-header-time-changes').html '<i class="spinner spinner-margin"></i>'
filterLines: (e, methodName, extra) ->
state: @state.toJSON()
showSettings: @showSettings
component: component
- currentIssue: @options.main.currentIssue
- period: @options.main.period?.toJSON()
\ No newline at end of file
+ currentIssue: @options.main.currentIssue
\ No newline at end of file
initialize: (options) ->
super
+ @main = options.main
@state = options.state
@component = options.component
@settings = options.settings
_.extend super,
state: @state.toJSON()
component: @component.toJSON()
- settings: @settings.toJSON()
\ No newline at end of file
+ settings: @settings.toJSON()
+ periods: @main.periods.toJSON()
\ No newline at end of file
'backbone.marionette'
'templates/component-viewer'
'component-viewer/header/base-header'
+ 'component-viewer/time-changes-popup'
], (
Marionette
Templates
BaseHeaderView
+ TimeChangesPopupView
) ->
$ = jQuery
events:
'click .js-issues-bulk-change': 'issuesBulkChange'
+ 'click .js-issues-time-changes': 'issuesTimeChanges'
'click .js-filter-current-issue': 'filterByCurrentIssue'
'click .js-filter-all-issues': 'filterByAllIssues'
openModalWindow url, {}
- filterByCurrentIssue: (e) -> @header.filterLines e, 'filterByCurrentIssue'
- filterByAllIssues: (e) -> @header.filterLines e, 'filterByAllIssues'
- filterByFixedIssues: (e) -> @header.filterLines e, 'filterByFixedIssues'
- filterByUnresolvedIssues: (e) -> @header.filterLines e, 'filterByUnresolvedIssues'
- filterByFalsePositiveIssues: (e) -> @header.filterLines e, 'filterByFalsePositiveIssues'
+ issuesTimeChanges: (e) ->
+ e.stopPropagation()
+ $('body').click()
+ popup = new TimeChangesPopupView
+ triggerEl: $(e.currentTarget)
+ main: @options.main
+ bottom: true
+ popup.render()
+ popup.on 'change', (period) => @main.enableIssuesPeriod period
- filterByRule: (e) -> @header.filterLines e, 'filterByRule', $(e.currentTarget).data 'rule'
- filterByBlockerIssues: (e) -> @header.filterLines e, 'filterByBlockerIssues'
- filterByCriticalIssues: (e) -> @header.filterLines e, 'filterByCriticalIssues'
- filterByMajorIssues: (e) -> @header.filterLines e, 'filterByMajorIssues'
- filterByMinorIssues: (e) -> @header.filterLines e, 'filterByMinorIssues'
- filterByInfoIssues: (e) -> @header.filterLines e, 'filterByInfoIssues'
\ No newline at end of file
+ filterByCurrentIssue: (e) ->
+ @header.filterLines e, 'filterByCurrentIssue'
+ @state.set 'activeHeaderItem', '.js-filter-current-issues'
+
+
+ filterByAllIssues: (e) ->
+ @header.filterLines e, 'filterByAllIssues'
+ @state.set 'activeHeaderItem', '.js-filter-all-issues'
+
+
+ filterByFixedIssues: (e) ->
+ @header.filterLines e, 'filterByFixedIssues'
+ @state.set 'activeHeaderItem', '.js-filter-fixed-issues'
+
+
+ filterByUnresolvedIssues: (e) ->
+ @header.filterLines e, 'filterByUnresolvedIssues'
+ @state.set 'activeHeaderItem', '.js-filter-unresolved-issues'
+
+
+ filterByFalsePositiveIssues: (e) ->
+ @header.filterLines e, 'filterByFalsePositiveIssues'
+ @state.set 'activeHeaderItem', '.js-filter-false-positive-issues'
+
+
+ filterByRule: (e) ->
+ rule = $(e.currentTarget).data 'rule'
+ @header.filterLines e, 'filterByRule', rule
+ @state.set 'activeHeaderItem', ".js-filter-rule[data-rule='#{rule}']"
+
+
+ filterByBlockerIssues: (e) ->
+ @header.filterLines e, 'filterByBlockerIssues'
+ @state.set 'activeHeaderItem', '.js-filter-BLOCKER-issues'
+
+
+ filterByCriticalIssues: (e) ->
+ @header.filterLines e, 'filterByCriticalIssues'
+ @state.set 'activeHeaderItem', '.js-filter-CRITICAL-issues'
+
+
+ filterByMajorIssues: (e) ->
+ @header.filterLines e, 'filterByMajorIssues'
+ @state.set 'activeHeaderItem', '.js-filter-MAJOR-issues'
+
+
+ filterByMinorIssues: (e) ->
+ @header.filterLines e, 'filterByMinorIssues'
+ @state.set 'activeHeaderItem', '.js-filter-MINOR-issues'
+
+
+ filterByInfoIssues: (e) ->
+ @header.filterLines e, 'filterByInfoIssues'
+ @state.set 'activeHeaderItem', '.js-filter-INFO-issues'
+
+
+ serializeData: ->
+ _.extend super, period: @state.get('issuesPeriod')?.toJSON()
\ No newline at end of file
triggerEl: $(e.currentTarget)
collection: new Backbone.Collection data.files
test: test
- main: @options.main
+ main: @main
popup.render()
\ No newline at end of file
model: @source
main: @
- @period = null
@periods = new Backbone.Collection [], model: Period
@headerRegion.show @headerView
- requestComponent: (key, clear = false) ->
- STATE_FIELDS = ['canBulkChange', 'canMarkAsFavourite', 'scmAvailable']
+ requestComponent: (key, clear = false, full = true) ->
+ STATE_FIELDS = ['canBulkChange', 'canMarkAsFavourite', 'tabs']
COMPONENT_FIELDS = ['key', 'name', 'path', 'q', 'projectName', 'subProjectName', 'measures', 'fav']
$.get API_COMPONENT, key: key, (data) =>
@component.set 'dir', utils.splitLongName(data.path).dir
@component.set 'isUnitTest', data.q == 'UTS'
+
# State
stateAttributes = {}
STATE_FIELDS.forEach (f) -> stateAttributes[f] = data[f]
stateAttributes.rules = _.sortBy rules, 'name'
severities = data.severities.map (r) -> key: r[0], name: r[1], count: r[2]
stateAttributes.severities = utils.sortSeverities severities
- @state.clear silent: true
- @state.set _.defaults stateAttributes, @state.defaults
+ if full
+ @state.clear silent: true
+ @state.set _.defaults stateAttributes, @state.defaults
+ else
+ @state.set stateAttributes
- # Periods
- @periods.reset [{}]
- data.periods.forEach (p) => @periods.add key: p[0], label: p[1], sinceDate: new Date p[2]
- @period = @periods.at 0
+ if full
+ # Periods
+ @periods.reset [{}]
+ data.periods.forEach (p) => @periods.add key: p[0], label: p[1], sinceDate: new Date p[2]
requestMeasures: (key) ->
metrics = [SOURCE_METRIC_LIST, COVERAGE_METRIC_LIST, ISSUES_METRIC_LIST, DUPLICATIONS_METRIC_LIST].join ','
else
metrics = [ISSUES_METRIC_LIST, TESTS_METRIC_LIST]
- $.get API_MEASURES, resource: key, metrics: metrics, (data) =>
+ data = resource: key, metrics: metrics
+ $.get API_MEASURES, data, (data) =>
measuresList = data[0].msr || []
measures = @component.get 'measures'
measuresList.forEach (m) ->
@render()
- enablePeriod: (period) ->
- @period = @periods.findWhere key: period
- @render()
-
-
showAllLines: ->
@sourceView.resetShowBlocks()
@sourceView.showBlocks.push from: 0, to: _.size @source.get 'source'
define [], () ->
$ = jQuery
+ API_COMPONENT = "#{baseUrl}/api/components/app"
API_ISSUES = "#{baseUrl}/api/issues/search"
LINES_AROUND_ISSUE = 4
@sourceView.render()
+ requestIssuesPeriod: (key, period) ->
+ $.get API_COMPONENT, key: key, period: period, (data) =>
+ rules = data.rules.map (r) -> key: r[0], name: r[1], count: r[2]
+ severities = data.severities.map (r) -> key: r[0], name: r[1], count: r[2]
+ @state.set rules: rules, severities: severities
+
+
+ enableIssuesPeriod: (periodKey) ->
+ period = if periodKey == '' then null else @periods.findWhere key: periodKey
+ @state.set 'issuesPeriod', period
+ if period?
+ @requestIssuesPeriod(@key, period.get('key')).done => @headerView.render()
+ else
+ @requestComponent(@key, false, false).done => @headerView.render()
+
+
filterLinesByIssues: ->
issues = @source.get 'issues'
@sourceView.resetShowBlocks()
filterByIssues: (predicate, requestIssues = true) ->
+ issuesPeriod = @state.get('issuesPeriod')
+ if issuesPeriod
+ p = predicate
+ predicate = (issue) =>
+ (new Date(issue.creationDate) >= issuesPeriod.get('sinceDate')) && p issue
+
if requestIssues && !@state.get 'hasIssues'
@requestIssues(@key).done => @_filterByIssues(predicate)
else
# Current Issue
filterByCurrentIssue: -> @filterByIssues ((issue) => issue.key == @currentIssue), false
+
# All Issues
filterByAllIssues: -> @filterByIssues -> true
enablePeriod: (e) ->
period = $(e.currentTarget).data 'period'
- @options.main.enablePeriod period
+ @trigger 'change', period
serializeData: ->
<span data-scope="basic" class="js-toggle-coverage component-viewer-header-measures-toggle-scope inactive"></span>
<a data-scope="basic" class="component-viewer-header-measures-expand">
<div class="component-viewer-header-measure">
- <span class="component-viewer-header-measure-value">{{component.measures.fNcloc}}</span>
+ <span class="component-viewer-header-measure-value">{{default component.measures.fNcloc '–'}}</span>
<span class="component-viewer-header-measure-label">{{t 'metric.ncloc.name'}}</span>
</div>
<i class="icon-dropdown"></i>
<div class="component-viewer-header-measures-scope">
<a data-scope="issues" class="component-viewer-header-measures-expand">
<div class="component-viewer-header-measure">
- <span class="component-viewer-header-measure-value">{{default component.measures.fDebt 0}}</span>
+ <span class="component-viewer-header-measure-value">{{default component.measures.fDebt '–'}}</span>
<span class="component-viewer-header-measure-label">{{t 'component_viewer.header.debt'}}</span>
</div>
{{#if component.measures.fIssues}}
class="js-toggle-issues component-viewer-header-measures-toggle-scope {{#if settings.issues}}active{{/if}}"></a>
</div>
- {{#unless component.isUnitTest}}
- {{#if component.measures.fCoverage}}
- <div class="component-viewer-header-measures-scope">
- <a data-scope="coverage" class="component-viewer-header-measures-expand">
- <div class="component-viewer-header-measure">
- <span class="component-viewer-header-measure-value">{{component.measures.fCoverage}}</span>
- <span class="component-viewer-header-measure-label">{{t 'metric.coverage.name'}}</span>
- </div>
- <i class="icon-dropdown"></i>
- </a>
- <a data-scope="coverage" title="{{t 'component_viewer.header.toggle_coverage'}}"
- class="js-toggle-coverage component-viewer-header-measures-toggle-scope {{#if settings.coverage}}active{{/if}}"></a>
- </div>
- {{/if}}
-
- {{#if component.measures.fDuplicationDensity}}
- <div class="component-viewer-header-measures-scope">
- <a data-scope="duplications" class="component-viewer-header-measures-expand">
- <div class="component-viewer-header-measure">
- <span class="component-viewer-header-measure-value">{{component.measures.fDuplicationDensity}}</span>
- <span class="component-viewer-header-measure-label">{{t 'metric.duplicated_lines_density.name'}}</span>
- </div>
- <i class="icon-dropdown"></i>
- </a>
- <a data-scope="duplications" title="{{t 'component_viewer.header.toggle_duplications'}}"
- class="js-toggle-duplications component-viewer-header-measures-toggle-scope {{#if settings.duplications}}active{{/if}}"></a>
- </div>
- {{/if}}
- {{/unless}}
+ {{#inArray state.tabs 'coverage'}}
+ <div class="component-viewer-header-measures-scope">
+ <a data-scope="coverage" class="component-viewer-header-measures-expand">
+ <div class="component-viewer-header-measure">
+ <span class="component-viewer-header-measure-value">{{default component.measures.fCoverage '–'}}</span>
+ <span class="component-viewer-header-measure-label">{{t 'metric.coverage.name'}}</span>
+ </div>
+ <i class="icon-dropdown"></i>
+ </a>
+ <a data-scope="coverage" title="{{t 'component_viewer.header.toggle_coverage'}}"
+ class="js-toggle-coverage component-viewer-header-measures-toggle-scope {{#if settings.coverage}}active{{/if}}"></a>
+ </div>
+ {{/inArray}}
- <div class="component-viewer-header-measures-scope">
- <span data-scope="scm" class="component-viewer-header-measures-expand">
- <div class="component-viewer-header-measure">
- <span class="component-viewer-header-measure-value"><i class="icon-calendar"></i></span>
- <span class="component-viewer-header-measure-label">SCM</span>
- </div>
- </span>
- <a data-scope="scm" title="{{t 'component_viewer.header.toggle_duplications'}}"
- class="js-toggle-scm component-viewer-header-measures-toggle-scope {{#if settings.scm}}active{{/if}}"></a>
- </div>
- </div>
+ {{#inArray state.tabs 'duplications'}}
+ <div class="component-viewer-header-measures-scope">
+ <a data-scope="duplications" class="component-viewer-header-measures-expand">
+ <div class="component-viewer-header-measure">
+ <span class="component-viewer-header-measure-value">{{default component.measures.fDuplicationDensity '–'}}</span>
+ <span class="component-viewer-header-measure-label">{{t 'metric.duplicated_lines_density.name'}}</span>
+ </div>
+ <i class="icon-dropdown"></i>
+ </a>
+ <a data-scope="duplications" title="{{t 'component_viewer.header.toggle_duplications'}}"
+ class="js-toggle-duplications component-viewer-header-measures-toggle-scope {{#if settings.duplications}}active{{/if}}"></a>
+ </div>
+ {{/inArray}}
- <div class="component-viewer-header-time-changes">
- <a>
- <i class="icon-period"></i>
- <div>{{#if period.key}}{{period.label}}{{else}}Time<br>Changes{{/if}}</div>
- </a>
+ {{#inArray state.tabs 'scm'}}
+ <div class="component-viewer-header-measures-scope">
+ <span data-scope="scm" class="component-viewer-header-measures-expand">
+ <div class="component-viewer-header-measure">
+ <span class="component-viewer-header-measure-value"><i class="icon-calendar"></i></span>
+ <span class="component-viewer-header-measure-label">SCM</span>
+ </div>
+ </span>
+ <a data-scope="scm" title="{{t 'component_viewer.header.toggle_duplications'}}"
+ class="js-toggle-scm component-viewer-header-measures-toggle-scope {{#if settings.scm}}active{{/if}}"></a>
+ </div>
+ {{/inArray}}
</div>
</div>
-{{#if component.measures.fIssues}}
+{{#ifNotEmpty state.severities}}
<div class="component-viewer-header-expanded-bar-section">
<div class="component-viewer-header-expanded-bar-section-title">
{{t 'component_viewer.measure_section.severities'}}
{{/each}}
</ul>
</div>
-{{/if}}
+{{/ifNotEmpty}}
-{{#if component.measures.fIssues}}
+{{#ifNotEmpty state.rules}}
<div class="component-viewer-header-expanded-bar-section">
<div class="component-viewer-header-expanded-bar-section-title">
{{t 'component_viewer.measure_section.rules'}}
{{/each}}
</ul>
</div>
-{{/if}}
+{{/ifNotEmpty}}
<div class="component-viewer-header-expanded-bar-section">
<div class="component-viewer-header-expanded-bar-section-title">
<i class="icon-chevron-right"></i>
</a></li>
{{/if}}
- {{#if component.measures.fIssues}}
- <li><a class="item js-filter-unresolved-issues">
- <span>{{t 'component_viewer.issues.unresolved_issues'}}</span>
- <span class="number">{{component.measures.fIssues}}</span>
- <i class="icon-chevron-right"></i>
- </a></li>
- {{/if}}
- {{#if component.measures.fIssues}}
- <li><a class="item js-filter-fixed-issues">
- <span>{{t 'component_viewer.issues.fixed_issues'}}</span>
- <i class="icon-chevron-right"></i>
- </a></li>
- {{/if}}
+ <li><a class="item js-filter-unresolved-issues">
+ <span>{{t 'component_viewer.issues.unresolved_issues'}}</span>
+ <i class="icon-chevron-right"></i>
+ </a></li>
+ <li><a class="item js-filter-fixed-issues">
+ <span>{{t 'component_viewer.issues.fixed_issues'}}</span>
+ <i class="icon-chevron-right"></i>
+ </a></li>
<li><a class="item js-filter-false-positive-issues">
<span>{{t 'component_viewer.issues.false_positive_issues'}}</span>
<span class="number">{{component.measures.false_positive_issues}}</span>
</ul>
</div>
-{{#if state.canBulkChange}}
<div class="component-viewer-header-expanded-bar-section component-viewer-header-expanded-bar-section-actions">
<div class="component-viewer-header-expanded-bar-section-title"> </div>
<ul class="component-viewer-header-expanded-bar-section-list">
- <li><a class="link-action js-issues-bulk-change">
- <span><i class="icon-bulk-change"></i> {{t 'bulk_change'}}</span>
+ <li><a class="link-action js-issues-time-changes">
+ <span><i class="icon-period"></i>
+ {{#if period}}Added {{period.label}}{{else}}Time Changes{{/if}}</span>
+
</a></li>
+ {{#if state.canBulkChange}}
+ <li><a class="link-action js-issues-bulk-change">
+ <span><i class="icon-bulk-change"></i> {{t 'bulk_change'}}</span>
+ </a></li>
+ {{/if}}
</ul>
</div>
-{{/if}}
\ No newline at end of file
});
Handlebars.registerHelper('percent', function(value, total) {
- return '' + ((value || 0) / total * 100) + '%';
+ if (total > 0) {
+ return '' + ((value || 0) / total * 100) + '%';
+ } else {
+ return '0%';
+ }
});
Handlebars.registerHelper('eq', function(v1, v2, options) {
}
});
+ Handlebars.registerHelper('ifMeasureShouldBeShown', function(measure, period, options) {
+ if (measure != null || period != null) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
+ });
+
});
& > a { display: block; }
}
-.component-viewer-header-time-changes {
- float: right;
- max-width: 180px;
-
- & > a {
- display: block;
- padding: 14px 10px;
- border-right: 1px solid @barBorderColor;
- font-size: @smallFontSize;
- .trans;
-
- &:hover { background-color: @barBorderColor; }
-
- & > i {
- display: block;
- float: left;
- margin-top: 8px;
- margin-right: 4px;
- }
-
- & > div {
- padding: 2px 0;
- overflow: hidden;
- }
- }
-}
-
.component-viewer-header-expanded-bar {
display: none;
.clearfix;
.component-viewer-header-expanded-bar-section-actions {
margin-left: 15px;
+
+ .component-viewer-header-expanded-bar-section-list > li {
+ padding: 4px 0;
+ line-height: 1.5;
+ }
}
.component-viewer-header-expanded-bar-section-title {