Merge pull request #1021 from opf/feature/ui-components-timeline-custom-fields
Feature/ui components timeline custom fieldspull/1040/head
commit
bbb9deb9d3
@ -1,17 +0,0 @@ |
|||||||
angular.module('openproject.timelines.directives') |
|
||||||
|
|
||||||
.directive('optionColumn', [function() { |
|
||||||
return { |
|
||||||
restrict: 'A', |
|
||||||
scope: true, |
|
||||||
compile: function(tElement, tAttrs, transclude) { |
|
||||||
return { |
|
||||||
pre: function(scope, iElement, iAttrs, controller) { |
|
||||||
scope.isDateOption = function(option) { |
|
||||||
return (option === 'start_date' || option === 'due_date'); |
|
||||||
}; |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
}; |
|
||||||
}]); |
|
@ -0,0 +1,71 @@ |
|||||||
|
angular.module('openproject.timelines.directives') |
||||||
|
|
||||||
|
.constant('WORK_PACKAGE_DATE_COLUMNS', ['start_date', 'due_date']) |
||||||
|
.directive('timelineColumn', ['WORK_PACKAGE_DATE_COLUMNS', 'I18n', 'CustomFieldHelper', function(WORK_PACKAGE_DATE_COLUMNS, I18n, CustomFieldHelper) { |
||||||
|
return { |
||||||
|
restrict: 'A', |
||||||
|
scope: { |
||||||
|
rowObject: '=', |
||||||
|
columnName: '=', |
||||||
|
timeline: '=', |
||||||
|
customFields: '=' |
||||||
|
}, |
||||||
|
templateUrl: '/templates/timelines/timeline_column.html', |
||||||
|
link: function(scope, element) { |
||||||
|
scope.isDateColumn = WORK_PACKAGE_DATE_COLUMNS.indexOf(scope.columnName) !== -1; |
||||||
|
|
||||||
|
scope.historicalDateKind = getHistoricalDateKind(scope.rowObject, scope.columnName); |
||||||
|
|
||||||
|
if (CustomFieldHelper.isCustomFieldKey(scope.columnName)) { |
||||||
|
// watch custom field because they are loaded after the rows are being iterated
|
||||||
|
scope.$watch('timeline.custom_fields', function() { |
||||||
|
scope.columnData = getCustomFieldColumnData(scope.rowObject, scope.columnName, scope.customFields, scope.timeline.users); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
scope.columnData = getColumnData(); |
||||||
|
} |
||||||
|
|
||||||
|
function getHistoricalDateKind(object, value) { |
||||||
|
if (!object.does_historical_differ()) return; |
||||||
|
|
||||||
|
var newDate = object[value]; |
||||||
|
var oldDate = object.historical()[value]; |
||||||
|
|
||||||
|
if (oldDate && newDate) { |
||||||
|
return (newDate < oldDate ? 'postponed' : 'preponed'); |
||||||
|
} |
||||||
|
return "changed"; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function getColumnData() { |
||||||
|
var map = { |
||||||
|
"type": "getTypeName", |
||||||
|
"status": "getStatusName", |
||||||
|
"responsible": "getResponsibleName", |
||||||
|
"assigned_to": "getAssignedName", |
||||||
|
"project": "getProjectName" |
||||||
|
}; |
||||||
|
|
||||||
|
switch(scope.columnName) { |
||||||
|
case 'start_date': |
||||||
|
return scope.rowObject.start_date; |
||||||
|
case 'due_date': |
||||||
|
return scope.rowObject.due_date; |
||||||
|
default: |
||||||
|
return scope.rowObject[map[scope.columnName]](); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function getCustomFieldColumnData(object, customFieldName, customFields, users) { |
||||||
|
if(!customFields) return; // custom_fields provides necessary meta information about the custom field column
|
||||||
|
|
||||||
|
var customField = customFields[CustomFieldHelper.getCustomFieldId(customFieldName)]; |
||||||
|
|
||||||
|
if (customField) { |
||||||
|
return CustomFieldHelper.formatCustomFieldValue(object[customFieldName], customField.field_format, users); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
}]); |
@ -0,0 +1,25 @@ |
|||||||
|
angular.module('openproject.timelines.directives') |
||||||
|
|
||||||
|
.directive('timelineColumnName', ['I18n', 'CustomFieldHelper', function(I18n, CustomFieldHelper) { |
||||||
|
return { |
||||||
|
restrict: 'A', |
||||||
|
scope: { |
||||||
|
columnName: '=', |
||||||
|
customFields: '=', |
||||||
|
localePrefix: '@' |
||||||
|
}, |
||||||
|
link: function(scope, element) { |
||||||
|
if (CustomFieldHelper.isCustomFieldKey(scope.columnName)) { |
||||||
|
scope.$watch('customFields', function(){ |
||||||
|
var customFieldId = CustomFieldHelper.getCustomFieldId(scope.columnName); |
||||||
|
if (scope.customFields && scope.customFields[customFieldId]) { |
||||||
|
element.html(scope.customFields[customFieldId].name); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
element.html(I18n.t(scope.localePrefix + '.' + scope.columnName)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}; |
||||||
|
}]); |
@ -1,78 +0,0 @@ |
|||||||
angular.module('openproject.uiComponents') |
|
||||||
|
|
||||||
.filter('historicalDateKind', function() { |
|
||||||
return function(object, dateOption) { |
|
||||||
if (!object.does_historical_differ()) return; |
|
||||||
|
|
||||||
var newDate = object[dateOption]; |
|
||||||
var oldDate = object.historical()[dateOption]; |
|
||||||
|
|
||||||
if (oldDate && newDate) { |
|
||||||
return (newDate < oldDate ? 'postponed' : 'preponed'); |
|
||||||
} |
|
||||||
return "changed"; |
|
||||||
}; |
|
||||||
}) |
|
||||||
|
|
||||||
// timelines
|
|
||||||
.filter('getOptionColumn', function() { |
|
||||||
var map = { |
|
||||||
"type": "getTypeName", |
|
||||||
"status": "getStatusName", |
|
||||||
"responsible": "getResponsibleName", |
|
||||||
"assigned_to": "getAssignedName", |
|
||||||
"project": "getProjectName" |
|
||||||
}; |
|
||||||
|
|
||||||
return function(object, option) { |
|
||||||
switch(option) { |
|
||||||
case 'start_date': |
|
||||||
return object.start_date; |
|
||||||
case 'due_date': |
|
||||||
return object.due_date; |
|
||||||
default: |
|
||||||
return object[map[option]](); |
|
||||||
} |
|
||||||
}; |
|
||||||
}); |
|
||||||
|
|
||||||
// TODO integrate custom field columns as can be seen in the example provided by the code copied from ui.js
|
|
||||||
// ...
|
|
||||||
// function booleanCustomFieldValue(value) {
|
|
||||||
// if (value) {
|
|
||||||
// if (value === "1") {
|
|
||||||
// return timeline.i18n("general_text_Yes")
|
|
||||||
// } else if (value === "0") {
|
|
||||||
// return timeline.i18n("general_text_No")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function formatCustomFieldValue(value, custom_field_id) {
|
|
||||||
// switch(timeline.custom_fields[custom_field_id].field_format) {
|
|
||||||
// case "bool":
|
|
||||||
// return booleanCustomFieldValue(value);
|
|
||||||
// case "user":
|
|
||||||
// if (timeline.users[value])
|
|
||||||
// return timeline.users[value].name;
|
|
||||||
// default:
|
|
||||||
// return value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function getCustomFieldValue(data, custom_field_name) {
|
|
||||||
// var custom_field_id = parseInt(custom_field_name.substr(3), 10), value = data[custom_field_name];
|
|
||||||
|
|
||||||
// if (value) {
|
|
||||||
// return jQuery('<span class="tl-column">' + timeline.escape(formatCustomFieldValue(value, custom_field_id)) + '</span>');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var timeline = this;
|
|
||||||
// return {
|
|
||||||
// all: ['due_date', 'type', 'status', 'responsible', 'start_date'],
|
|
||||||
// general: function (data, val) {
|
|
||||||
// if (val.substr(0, 3) === "cf_") {
|
|
||||||
// return getCustomFieldValue(data, val);
|
|
||||||
// }
|
|
||||||
// ...
|
|
@ -0,0 +1,36 @@ |
|||||||
|
angular.module('openproject.uiComponents') |
||||||
|
|
||||||
|
.constant('CUSTOM_FIELD_PREFIX', 'cf_') |
||||||
|
.service('CustomFieldHelper', ['CUSTOM_FIELD_PREFIX', 'I18n', function(CUSTOM_FIELD_PREFIX, I18n) { |
||||||
|
CustomFieldHelper = { |
||||||
|
isCustomFieldKey: function(key) { |
||||||
|
return key.substr(0, CUSTOM_FIELD_PREFIX.length) === CUSTOM_FIELD_PREFIX; |
||||||
|
}, |
||||||
|
getCustomFieldId: function(cfKey) { |
||||||
|
return parseInt(cfKey.substr(CUSTOM_FIELD_PREFIX.length, 10), 10); |
||||||
|
}, |
||||||
|
booleanCustomFieldValue: function(value) { |
||||||
|
if (value) { |
||||||
|
if (value === '1') { |
||||||
|
return I18n.t('js.general_text_Yes'); |
||||||
|
} else if (value === '0') { |
||||||
|
return I18n.t('js.general_text_No'); |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
formatCustomFieldValue: function(value, fieldFormat, users) { |
||||||
|
switch(fieldFormat) { |
||||||
|
case 'bool': |
||||||
|
return CustomFieldHelper.booleanCustomFieldValue(value); |
||||||
|
case 'user': |
||||||
|
if (users[value]) |
||||||
|
return users[value].name; |
||||||
|
break; |
||||||
|
default: |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return CustomFieldHelper; |
||||||
|
}]); |
@ -0,0 +1,18 @@ |
|||||||
|
<span class="tl-historical" ng-show="rowObject.does_historical_differ(columnName)"> |
||||||
|
<a href="javascript://" title="{{I18n.t('js.timelines.change')}}" |
||||||
|
ng-class="[ |
||||||
|
'icon', |
||||||
|
'tl-icon-' + isDateColumn && historicalDateKind || 'tl-icon-changed' |
||||||
|
]"> |
||||||
|
{{rowObject.historical()[columnName] || I18n.t('js.timelines.empty')}} |
||||||
|
</a> |
||||||
|
<br/> |
||||||
|
</span> |
||||||
|
|
||||||
|
<span ng-class="[ |
||||||
|
'tl-column', |
||||||
|
isDateColumn && 'tl-current', |
||||||
|
isDateColumn && rowObject.does_historical_differ(columnName) && 'tl-' + (historicalDateKind) |
||||||
|
]"> |
||||||
|
{{columnData}} |
||||||
|
</span> |
Loading…
Reference in new issue