CRM-15578 - Mailing API - Extend test for "preview" action:
[civicrm-core.git] / js / angular-crmCaseType.js
CommitLineData
4c58e251
TO
1(function(angular, $, _) {
2
64790edd
TO
3 var partialUrl = function(relPath) {
4 return CRM.resourceUrls['civicrm'] + '/partials/crmCaseType/' + relPath;
8fc6fba7 5 };
64790edd 6
51d499e1 7 var crmCaseType = angular.module('crmCaseType', ['ngRoute', 'ui.utils', 'crmUi', 'unsavedChanges']);
4c58e251 8
506cd414 9 // Note: This template will be passed to cloneDeep(), so don't put any funny stuff in here!
9be5fc34
TO
10 var newCaseTypeTemplate = {
11 title: "",
12 name: "",
13 is_active: "1",
14 weight: "1",
15 definition: {
16 activityTypes: [
4d8bbcf6
TO
17 {name: 'Open Case', max_instances: 1},
18 {name: 'Email'},
19 {name: 'Follow up'},
20 {name: 'Meeting'},
21 {name: 'Phone Call'}
9be5fc34
TO
22 ],
23 activitySets: [
24 {
25 name: 'standard_timeline',
26 label: 'Standard Timeline',
27 timeline: '1', // Angular won't bind checkbox correctly with numeric 1
28 activityTypes: [
29 {name: 'Open Case', status: 'Completed' }
30 ]
31 }
32 ],
33 caseRoles: [
34 { name: 'Case Coordinator', creator: '1', manager: '1'}
35 ]
36 }
4d74de55
TO
37 };
38
4c58e251
TO
39 crmCaseType.config(['$routeProvider',
40 function($routeProvider) {
b75c2546
TO
41 $routeProvider.when('/caseType', {
42 templateUrl: partialUrl('list.html'),
43 controller: 'CaseTypeListCtrl',
44 resolve: {
45 caseTypes: function($route, crmApi) {
46 return crmApi('CaseType', 'get', {});
47 }
48 }
49 });
4c58e251 50 $routeProvider.when('/caseType/:id', {
64790edd 51 templateUrl: partialUrl('edit.html'),
4d74de55
TO
52 controller: 'CaseTypeCtrl',
53 resolve: {
9625aad1
TO
54 apiCalls: function($route, crmApi) {
55 var reqs = {};
56 reqs.actStatuses = ['OptionValue', 'get', {
57 option_group_id: 'activity_status'
58 }];
59 reqs.actTypes = ['OptionValue', 'get', {
60 option_group_id: 'activity_type',
61 options: {
62 sort: 'name',
63 limit: 0
64 }
65 }];
66 reqs.relTypes = ['RelationshipType', 'get', {
67 options: {
68 sort: CRM.crmCaseType.REL_TYPE_CNAME,
69 limit: 0
70 }
71 }];
72 if ($route.current.params.id !== 'new') {
73 reqs.caseType = ['CaseType', 'getsingle', {
74 id: $route.current.params.id
75 }];
87dcd909 76 }
9625aad1 77 return crmApi(reqs);
4d74de55
TO
78 }
79 }
4c58e251
TO
80 });
81 }
82 ]);
83
95fd24c0
TO
84 // Add a new record by name.
85 // Ex: <crmAddName crm-options="['Alpha','Beta','Gamma']" crm-var="newItem" crm-on-add="callMyCreateFunction(newItem)" />
8fc6fba7 86 crmCaseType.directive('crmAddName', function() {
95fd24c0
TO
87 return {
88 restrict: 'AE',
bafce1db
TO
89 template: '<input class="add-activity" type="hidden" />',
90 link: function(scope, element, attrs) {
91 /// Format list of options for select2's "data"
92 var getFormattedOptions = function() {
93 return {
94 results: _.map(scope[attrs.crmOptions], function(option){
95 return {id: option, text: option};
96 })
97 };
98 };
99
100 var input = $('input', element);
101
102 scope._resetSelection = function() {
103 $(input).select2('close');
104 $(input).select2('val', '');
105 scope[attrs.crmVar] = '';
106 };
107
108 $(input).select2({
109 data: getFormattedOptions,
110 createSearchChoice: function(term) {
111 return {id: term, text: term};
112 }
113 });
114 $(input).on('select2-selecting', function(e) {
115 scope[attrs.crmVar] = e.val;
116 scope.$evalAsync(attrs.crmOnAdd);
117 scope.$evalAsync('_resetSelection()');
118 e.preventDefault();
119 });
60dd172b
TO
120
121 scope.$watch(attrs.crmOptions, function(value) {
122 $(input).select2('data', getFormattedOptions);
123 $(input).select2('val', '');
124 });
bafce1db 125 }
95fd24c0
TO
126 };
127 });
128
9625aad1 129 crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls) {
64790edd 130 $scope.partialUrl = partialUrl;
76e4acb8 131
9625aad1
TO
132 $scope.activityStatuses = _.values(apiCalls.actStatuses.values);
133 $scope.activityTypes = apiCalls.actTypes.values;
134 $scope.activityTypeNames = _.pluck(apiCalls.actTypes.values, 'name');
135 $scope.relationshipTypeNames = _.pluck(apiCalls.relTypes.values, CRM.crmCaseType.REL_TYPE_CNAME); // CRM_Case_XMLProcessor::REL_TYPE_CNAME
1317b266 136 $scope.locks = {caseTypeName: true, activitySetName: true};
dc7a657e 137
76e4acb8
TO
138 $scope.workflows = {
139 'timeline': 'Timeline',
b387506c 140 'sequence': 'Sequence'
76e4acb8
TO
141 };
142
9625aad1 143 $scope.caseType = apiCalls.caseType ? apiCalls.caseType : _.cloneDeep(newCaseTypeTemplate);
87dcd909 144 $scope.caseType.definition = $scope.caseType.definition || [];
4d74de55
TO
145 $scope.caseType.definition.activityTypes = $scope.caseType.definition.activityTypes || [];
146 $scope.caseType.definition.activitySets = $scope.caseType.definition.activitySets || [];
147 $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || [];
dc7a657e 148 window.ct = $scope.caseType;
4c58e251 149
76e4acb8
TO
150 $scope.addActivitySet = function(workflow) {
151 var activitySet = {};
152 activitySet[workflow] = '1';
153 activitySet.activityTypes = [];
154
155 var offset = 1;
156 var names = _.pluck($scope.caseType.definition.activitySets, 'name');
157 while (_.contains(names, workflow + '_' + offset)) offset++;
158 activitySet.name = workflow + '_' + offset;
159 activitySet.label = (offset == 1 ) ? $scope.workflows[workflow] : ($scope.workflows[workflow] + ' #' + offset);
160
161 $scope.caseType.definition.activitySets.push(activitySet);
162 _.defer(function() {
163 $('.crmCaseType-acttab').tabs('refresh').tabs({active: -1});
164 });
165 };
166
d7c25f6c
TO
167 /// Add a new activity entry to an activity-set
168 $scope.addActivity = function(activitySet, activityType) {
169 activitySet.activityTypes.push({
183241d8 170 name: activityType,
171 status: 'Scheduled',
172 reference_activity: 'Open Case',
173 reference_offset: '1',
174 reference_select: 'newest'
d7c25f6c 175 });
60dd172b
TO
176 if (!_.contains($scope.activityTypeNames, activityType)) {
177 $scope.activityTypeNames.push(activityType);
178 }
d7c25f6c
TO
179 };
180
181 /// Add a new top-level activity-type entry
182 $scope.addActivityType = function(activityType) {
183 var names = _.pluck($scope.caseType.definition.activityTypes, 'name');
184 if (!_.contains(names, activityType)) {
185 $scope.caseType.definition.activityTypes.push({
186 name: activityType
187 });
60dd172b
TO
188
189 }
190 if (!_.contains($scope.activityTypeNames, activityType)) {
191 $scope.activityTypeNames.push(activityType);
d7c25f6c
TO
192 }
193 };
194
8c7e0ae8
TO
195 /// Add a new role
196 $scope.addRole = function(roles, roleName) {
bafce1db
TO
197 var names = _.pluck($scope.caseType.definition.caseRoles, 'name');
198 if (!_.contains(names, roleName)) {
199 roles.push({
200 name: roleName
201 });
202 }
60dd172b
TO
203 if (!_.contains($scope.relationshipTypeNames, roleName)) {
204 $scope.relationshipTypeNames.push(roleName);
205 }
8c7e0ae8
TO
206 };
207
4c58e251
TO
208 $scope.onManagerChange = function(managerRole) {
209 angular.forEach($scope.caseType.definition.caseRoles, function(caseRole) {
210 if (caseRole != managerRole) {
211 caseRole.manager = '0';
212 }
213 });
214 };
215
216 $scope.removeItem = function(array, item) {
217 var idx = _.indexOf(array, item);
218 if (idx != -1) {
219 array.splice(idx, 1);
220 }
221 };
222
b40b4114
TO
223 $scope.isForkable = function() {
224 return !$scope.caseType.id || $scope.caseType.is_forkable
225 };
226
5d973e24
TO
227 $scope.isNewActivitySetAllowed = function(workflow) {
228 switch (workflow) {
229 case 'timeline':
230 return true;
b387506c
TO
231 case 'sequence':
232 return 0 == _.where($scope.caseType.definition.activitySets, {sequence: '1'}).length;
5d973e24 233 default:
bba9b4f0 234 CRM.console('warn', 'Denied access to unrecognized workflow: (' + workflow + ')');
5d973e24
TO
235 return false;
236 }
237 };
238
259a7652
TO
239 $scope.isActivityRemovable = function(activitySet, activity) {
240 if (activitySet.name == 'standard_timeline' && activity.name == 'Open Case') {
241 return false;
242 } else {
243 return true;
244 }
245 };
246
f42b448f
TO
247 $scope.isValidName = function(name) {
248 return !name || name.match(/^[a-zA-Z0-9_]+$/);
249 };
250
4c58e251 251 $scope.getWorkflowName = function(activitySet) {
76e4acb8
TO
252 var result = 'Unknown';
253 _.each($scope.workflows, function(value, key) {
254 if (activitySet[key]) result = value;
255 });
256 return result;
4c58e251
TO
257 };
258
259 /**
260 * Determine which HTML partial to use for a particular
261 *
262 * @return string URL of the HTML partial
263 */
264 $scope.activityTableTemplate = function(activitySet) {
265 if (activitySet.timeline) {
64790edd 266 return partialUrl('timelineTable.html');
b387506c
TO
267 } else if (activitySet.sequence) {
268 return partialUrl('sequenceTable.html');
4c58e251
TO
269 } else {
270 return '';
271 }
272 };
273
274 $scope.dump = function() {
275 console.log($scope.caseType);
76e4acb8
TO
276 };
277
aa1a7c2e 278 $scope.save = function() {
c7bccb5f 279 var result = crmApi('CaseType', 'create', $scope.caseType, true);
280 result.success(function(data) {
281 if (data.is_error == 0) {
282 $scope.caseType.id = data.id;
1ab5b88e 283 window.location.href = '#/caseType';
c7bccb5f 284 }
285 });
aa1a7c2e
TO
286 };
287
76e4acb8
TO
288 $scope.$watchCollection('caseType.definition.activitySets', function() {
289 _.defer(function() {
8fc6fba7 290 $('.crmCaseType-acttab').tabs('refresh');
76e4acb8
TO
291 });
292 });
685acae4 293
294 var updateCaseTypeName = function () {
295 if (!$scope.caseType.id && $scope.locks.caseTypeName) {
296 // Should we do some filtering? Lowercase? Strip whitespace?
a5ca1f48 297 var t = $scope.caseType.title ? $scope.caseType.title : '';
298 $scope.caseType.name = t.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '').toLowerCase();
685acae4 299 }
300 };
301 $scope.$watch('locks.caseTypeName', updateCaseTypeName);
302 $scope.$watch('caseType.title', updateCaseTypeName);
b40b4114
TO
303
304 if (!$scope.isForkable()) {
305 CRM.alert(ts('The CiviCase XML file for this case-type prohibits editing the definition.'));
306 }
4c58e251
TO
307 });
308
b75c2546
TO
309 crmCaseType.controller('CaseTypeListCtrl', function($scope, crmApi, caseTypes) {
310 $scope.caseTypes = caseTypes.values;
4b8c8b42
TO
311 $scope.toggleCaseType = function (caseType) {
312 caseType.is_active = (caseType.is_active == '1') ? '0' : '1';
313 crmApi('CaseType', 'create', caseType, true)
314 .then(function (data) {
315 if (data.is_error) {
316 caseType.is_active = (caseType.is_active == '1') ? '0' : '1'; // revert
317 $scope.$digest();
318 }
319 });
320 };
321 $scope.deleteCaseType = function (caseType) {
eb8e4c2d
TO
322 crmApi('CaseType', 'delete', {id: caseType.id}, {
323 error: function (data) {
324 CRM.alert(data.error_message, ts('Error'));
325 }
326 })
4b8c8b42
TO
327 .then(function (data) {
328 if (!data.is_error) {
329 delete caseTypes.values[caseType.id];
330 $scope.$digest();
331 }
332 });
333 };
470a458e
TO
334 $scope.revertCaseType = function (caseType) {
335 caseType.definition = 'null';
336 caseType.is_forked = '0';
337 crmApi('CaseType', 'create', caseType, true)
338 .then(function (data) {
339 if (data.is_error) {
340 caseType.is_forked = '1'; // restore
341 $scope.$digest();
342 }
343 });
344 };
b75c2546
TO
345 });
346
bba9b4f0 347})(angular, CRM.$, CRM._);