From 3304492780525ea1ad2203641c41f0bae78a333c Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Sat, 18 Jan 2020 14:50:25 -0500 Subject: [PATCH] Move exportui extension into core --- CRM/Export/Form/Map.php | 220 ++++++++++--------------- CRM/Export/Utils.php | 110 +++++++++++++ Civi/Angular/Manager.php | 1 + ang/exportui.ang.php | 23 +++ ang/exportui.css | 56 +++++++ ang/exportui/export.html | 30 ++++ ang/exportui/exportField.html | 15 ++ ang/exportui/exportSaveMapping.html | 27 +++ ang/exportui/exportui.js | 247 ++++++++++++++++++++++++++++ extension-compatibility.json | 5 + templates/CRM/Export/Form/Map.tpl | 11 +- templates/CRM/Export/Form/table.tpl | 76 --------- 12 files changed, 606 insertions(+), 215 deletions(-) create mode 100644 CRM/Export/Utils.php create mode 100644 ang/exportui.ang.php create mode 100644 ang/exportui.css create mode 100644 ang/exportui/export.html create mode 100644 ang/exportui/exportField.html create mode 100644 ang/exportui/exportSaveMapping.html create mode 100644 ang/exportui/exportui.js delete mode 100644 templates/CRM/Export/Form/table.tpl diff --git a/CRM/Export/Form/Map.php b/CRM/Export/Form/Map.php index 7f4bfa06bd..25dd3816ea 100644 --- a/CRM/Export/Form/Map.php +++ b/CRM/Export/Form/Map.php @@ -22,20 +22,6 @@ */ class CRM_Export_Form_Map extends CRM_Core_Form { - /** - * Mapper fields - * - * @var array - */ - protected $_mapperFields; - - /** - * Number of columns in import file - * - * @var int - */ - protected $_exportColumnCount; - /** * Loaded mapping ID * @@ -45,37 +31,45 @@ class CRM_Export_Form_Map extends CRM_Core_Form { /** * Build the form object. - * - * @return void */ public function preProcess() { - $this->_exportColumnCount = $this->get('exportColumnCount'); $this->_mappingId = $this->get('mappingId'); - if (!$this->_exportColumnCount) { - // Set default from saved mapping - if ($this->_mappingId) { - $mapping = new CRM_Core_DAO_MappingField(); - $mapping->mapping_id = $this->_mappingId; - $this->_exportColumnCount = $mapping->count(); - } - else { - $this->_exportColumnCount = 10; - } - } - else { - $this->_exportColumnCount += 10; + $contactTypes = array_column(CRM_Utils_Array::makeNonAssociative(CRM_Contact_BAO_ContactType::basicTypePairs(), 'id', 'text'), NULL, 'id'); + foreach (CRM_Contact_BAO_ContactType::subTypeInfo() as $subType) { + $contactTypes[$subType['parent']]['children'][] = [ + 'id' => $subType['name'], + 'text' => $subType['label'], + 'description' => $subType['description'] ?? NULL, + ]; } + $mappingTypeId = $this->get('mappingTypeId'); + $mappings = civicrm_api3('Mapping', 'get', ['return' => ['name', 'description'], 'mapping_type_id' => $mappingTypeId, 'options' => ['limit' => 0]]); + + Civi::resources()->addVars('exportUi', [ + 'fields' => CRM_Export_Utils::getExportFields($this->get('exportMode')), + 'contact_types' => array_values($contactTypes), + 'location_type_id' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_Address::buildOptions('location_type_id'), 'id', 'text'), + 'preview_data' => $this->getPreviewData(), + 'mapping_id' => $this->_mappingId, + 'mapping_description' => $mappings['values'][$this->_mappingId]['description'] ?? '', + 'mapping_type_id' => $mappingTypeId, + 'mapping_names' => CRM_Utils_Array::collect('name', $mappings['values']), + 'option_list' => [ + 'phone_type_id' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_Phone::buildOptions('phone_type_id'), 'id', 'text'), + 'website_type_id' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_Website::buildOptions('website_type_id'), 'id', 'text'), + 'im_provider_id' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_IM::buildOptions('provider_id'), 'id', 'text'), + ], + ]); + + // Bootstrap angular and load exportui app + $loader = new Civi\Angular\AngularLoader(); + $loader->setModules(['exportui']); + $loader->load(); } public function buildQuickForm() { - CRM_Core_BAO_Mapping::buildMappingForm($this, - 'Export', - $this->_mappingId, - $this->_exportColumnCount, - 2, - $this->get('exportMode') - ); + $this->add('hidden', 'export_field_map'); $this->addButtons([ [ @@ -83,128 +77,54 @@ class CRM_Export_Form_Map extends CRM_Core_Form { 'name' => ts('Previous'), ], [ - 'type' => 'next', - 'name' => ts('Export'), - 'spacing' => '          ', + 'type' => 'done', + 'icon' => 'fa-ban', + 'name' => ts('Return to Search'), ], [ - 'type' => 'done', - 'icon' => 'fa-times', - 'name' => ts('Done'), + 'type' => 'next', + 'icon' => 'fa-download', + 'name' => ts('Download File'), ], ]); } - /** - * Global validation rules for the form. - * - * @param array $fields - * Posted values of the form. - * - * @param $values - * @param int $mappingTypeId - * - * @return array - * list of errors to be posted back to the form - */ - public static function formRule($fields, $values, $mappingTypeId) { - $errors = []; - - if (!empty($fields['saveMapping']) && !empty($fields['_qf_Map_next'])) { - $nameField = CRM_Utils_Array::value('saveMappingName', $fields); - if (empty($nameField)) { - $errors['saveMappingName'] = ts('Name is required to save Export Mapping'); - } - else { - //check for Duplicate mappingName - if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { - $errors['saveMappingName'] = ts('Duplicate Export Mapping Name'); - } - } - } - - if (!empty($errors)) { - $_flag = 1; - $assignError = new CRM_Core_Page(); - $assignError->assign('mappingDetailsError', $_flag); - return $errors; - } - else { - return TRUE; + public function setDefaultValues() { + $defaults = []; + if ($this->_mappingId) { + $mappingFields = civicrm_api3('mappingField', 'get', ['mapping_id' => $this->_mappingId, 'options' => ['limit' => 0, 'sort' => 'column_number']]); + $defaults['export_field_map'] = json_encode(array_values($mappingFields['values'])); } + return $defaults; } /** - * Process the uploaded file. - * - * @return void + * Process the form submission. */ public function postProcess() { $params = $this->controller->exportValues($this->_name); $exportParams = $this->controller->exportValues('Select'); - $currentPath = CRM_Utils_System::currentPath(); - - $urlParams = NULL; - $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); - if (CRM_Utils_Rule::qfKey($qfKey)) { - $urlParams = "&qfKey=$qfKey"; - } - - //get the button name - $buttonName = $this->controller->getButtonName('done'); - $buttonName1 = $this->controller->getButtonName('next'); - if ($buttonName == '_qf_Map_done') { - $this->set('exportColumnCount', NULL); + // Redirect back to search if "done" button pressed + if ($this->controller->getButtonName('done') == '_qf_Map_done') { + $currentPath = CRM_Utils_System::currentPath(); + $urlParams = NULL; + $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); + if (CRM_Utils_Rule::qfKey($qfKey)) { + $urlParams = "&qfKey=$qfKey"; + } $this->controller->resetPage($this->_name); return CRM_Utils_System::redirect(CRM_Utils_System::url($currentPath, 'force=1' . $urlParams)); } - if ($this->controller->exportValue($this->_name, 'addMore')) { - $this->set('exportColumnCount', $this->_exportColumnCount); - return; - } - - $mapperKeys = $params['mapper'][1]; - - $mappedFields = []; - foreach ((array) $mapperKeys as $field) { - if (!empty($field[1])) { - $mappedFields[] = CRM_Core_BAO_Mapping::getMappingParams([], $field); - } - } - - if (!$mappedFields) { - $this->set('mappingId', NULL); - CRM_Utils_System::redirect(CRM_Utils_System::url($currentPath, '_qf_Map_display=true' . $urlParams)); - } - - if ($buttonName1 == '_qf_Map_next') { - if (!empty($params['updateMapping'])) { - //save mapping fields - CRM_Core_BAO_Mapping::saveMappingFields($params, $params['mappingId']); - } - - if (!empty($params['saveMapping'])) { - $mappingParams = [ - 'name' => $params['saveMappingName'], - 'description' => $params['saveMappingDesc'], - 'mapping_type_id' => $this->get('mappingTypeId'), - ]; - - $saveMapping = CRM_Core_BAO_Mapping::add($mappingParams); - - //save mapping fields - CRM_Core_BAO_Mapping::saveMappingFields($params, $saveMapping->id); - } - } + $selectedFields = json_decode($params['export_field_map'], TRUE); //get the csv file CRM_Export_BAO_Export::exportComponents($this->get('selectAll'), $this->get('componentIds'), (array) $this->get('queryParams'), $this->get(CRM_Utils_Sort::SORT_ORDER), - $mappedFields, + $selectedFields, $this->get('returnProperties'), $this->get('exportMode'), $this->get('componentClause'), @@ -216,6 +136,38 @@ class CRM_Export_Form_Map extends CRM_Core_Form { ); } + /** + * @return array + */ + protected function getPreviewData() { + $exportParams = $this->controller->exportValues('Select'); + $isPostalOnly = ( + isset($exportParams['postal_mailing_export']['postal_mailing_export']) && + $exportParams['postal_mailing_export']['postal_mailing_export'] == 1 + ); + $processor = new CRM_Export_BAO_ExportProcessor($this->get('exportMode'), NULL, $this->get('queryOperator'), $this->get('mergeSameHousehold'), $isPostalOnly, $this->get('mergeSameAddress')); + $processor->setComponentTable($this->get('componentTable')); + $processor->setComponentClause($this->get('componentClause')); + $data = $processor->getPreview(4); + $ids = CRM_Utils_Array::collect('id', $data); + $data = array_pad($data, 4, []); + + // Add location-type-specific data + if ($ids) { + foreach (['address', 'phone', 'email'] as $ent) { + foreach (civicrm_api3($ent, 'get', ['options' => ['limit' => 0], 'contact_id' => ['IN' => $ids]])['values'] as $loc) { + $row = array_search($loc['contact_id'], $ids); + $suffix = '_' . $loc['location_type_id'] . ($ent == 'phone' ? '_' . $loc['phone_type_id'] : ''); + CRM_Utils_Array::remove($loc, 'id', 'contact_id', 'location_type_id', 'phone_type_id'); + foreach ($loc as $name => $val) { + $data[$row][$name . $suffix] = $val; + } + } + } + } + return $data; + } + /** * Return a descriptive name for the page, used in wizard header * diff --git a/CRM/Export/Utils.php b/CRM/Export/Utils.php new file mode 100644 index 0000000000..adfed821b3 --- /dev/null +++ b/CRM/Export/Utils.php @@ -0,0 +1,110 @@ + ['text' => ts('Contact Fields'), 'is_contact' => TRUE], + 'address' => ['text' => ts('Address Fields'), 'is_contact' => TRUE], + 'communication' => ['text' => ts('Communication Fields'), 'is_contact' => TRUE], + ]; + $optionMap = [ + 'civicrm_website' => 'website_type_id', + 'civicrm_phone' => 'phone_type_id', + 'civicrm_im' => 'im_provider_id', + ]; + // Whitelist of field properties we actually care about; others will be discarded + $fieldProps = ['id', 'text', 'has_location', 'option_list', 'relationship_type_id', 'related_contact_type']; + $relTypes = civicrm_api3('RelationshipType', 'get', ['options' => ['limit' => 0]])['values']; + + // Add component fields + $compFields = []; + $compLabels = CRM_Core_BAO_Mapping::addComponentFields($compFields, 'Export', $exportMode); + foreach ($compLabels as $comp => $label) { + $categories[$comp] = ['text' => $label]; + foreach ($compFields[$comp] as $key => $field) { + $field['text'] = $field['title']; + $field['id'] = $key; + $categories[$comp]['children'][] = array_intersect_key($field, array_flip($fieldProps)); + } + } + + // Unset groups, tags, notes for component export + if ($exportMode != CRM_Export_Form_Select::CONTACT_EXPORT) { + foreach (array_keys($fieldGroups) as $contactType) { + CRM_Utils_Array::remove($fieldGroups[$contactType], 'groups', 'tags', 'notes'); + } + } + + // Now combine all those redundant lists of fields into a single list with categories + foreach ($fieldGroups as $contactType => $fields) { + // 'related' was like a poor-mans optgroup. + unset($fields['related']); + foreach ($fields as $key => $field) { + $group = 'contact'; + $field['text'] = $field['title']; + $field['id'] = $key; + $field['has_location'] = !empty($field['hasLocationType']); + if (isset($field['table_name']) && isset($optionMap[$field['table_name']])) { + $field['option_list'] = $optionMap[$field['table_name']]; + $group = 'communication'; + } + elseif (!empty($field['has_location'])) { + $group = 'address'; + } + if ($key == 'email') { + $group = 'communication'; + } + if (!empty($field['custom_group_id'])) { + $group = $field['custom_group_id']; + $categories[$group]['text'] = $field['groupTitle']; + $categories[$group]['is_contact'] = TRUE; + } + if (!empty($field['related'])) { + $group = 'related'; + $categories[$group]['text'] = ts('Related Contact Info'); + list($type, , $dir) = explode('_', $key); + $field['related_contact_type'] = $relTypes[$type]["contact_sub_type_$dir"] ?? $relTypes[$type]["contact_type_$dir"] ?? '*'; + // Skip relationship types targeting disabled contacts + if ($field['related_contact_type'] != '*' && !isset($fieldGroups[$field['related_contact_type']])) { + continue; + } + } + if (empty($categories[$group]['children'][$key])) { + // Discard unwanted field props to save space + $categories[$group]['children'][$key] = array_intersect_key($field, array_flip($fieldProps)); + } + // Set contact_type, which gets added to on every iteration + $categories[$group]['children'][$key]['contact_type'][] = $contactType; + // If a field applies to every contact type, remove the contact_type flag as it's redundant + if (count($fieldGroups) == count($categories[$group]['children'][$key]['contact_type'])) { + unset($categories[$group]['children'][$key]['contact_type']); + } + } + } + // We needed meaningful keys while organizing fields but if we send them client-side they'll just be in the way + foreach ($categories as &$category) { + $category['children'] = array_values($category['children']); + } + return array_values($categories); + } + +} diff --git a/Civi/Angular/Manager.php b/Civi/Angular/Manager.php index e5f169a385..4b21537d3f 100644 --- a/Civi/Angular/Manager.php +++ b/Civi/Angular/Manager.php @@ -98,6 +98,7 @@ class Manager { $angularModules['ui.sortable'] = include "$civicrm_root/ang/ui.sortable.ang.php"; $angularModules['unsavedChanges'] = include "$civicrm_root/ang/unsavedChanges.ang.php"; $angularModules['statuspage'] = include "$civicrm_root/ang/crmStatusPage.ang.php"; + $angularModules['exportui'] = include "$civicrm_root/ang/exportui.ang.php"; $angularModules['api4Explorer'] = include "$civicrm_root/ang/api4Explorer.ang.php"; $angularModules['api4'] = include "$civicrm_root/ang/api4.ang.php"; diff --git a/ang/exportui.ang.php b/ang/exportui.ang.php new file mode 100644 index 0000000000..81dafe4af3 --- /dev/null +++ b/ang/exportui.ang.php @@ -0,0 +1,23 @@ + 'civicrm', + 'js' => [ + 'ang/exportui/*.js', + 'ang/exportui/*/*.js', + ], + 'css' => [ + 'ang/exportui.css', + ], + 'partials' => [ + 'ang/exportui', + ], + 'basePages' => [], + 'requires' => [ + 'crmUi', + 'crmUtil', + 'ui.sortable', + 'dialogService', + ], + 'settings' => [], +]; diff --git a/ang/exportui.css b/ang/exportui.css new file mode 100644 index 0000000000..114d36107a --- /dev/null +++ b/ang/exportui.css @@ -0,0 +1,56 @@ +/* "fade-out" effect */ +div.crm-export-field-selector-outer { + position: relative; + overflow-x: hidden; +} +div.crm-export-field-selector-outer:after { + position: absolute; + top: 0; + right: 0; + height: 100%; + width: 20%; + content: ' '; + background-image: linear-gradient(to right, transparent, #efefe5); +} +table.crm-export-field-selector tbody tr { + background-color: #FAFAFA; +} +table.crm-export-field-selector tbody tr:nth-child(odd) { + background-color: #EFEFEF; +} +table.crm-export-field-selector tfoot tr { + background-color: white; + border-top: 2px solid #CFCEC3; +} +table.crm-export-field-selector tfoot tr td > span { + margin-left: 18px; +} +.crm-export-field-selector tbody td { + cursor: move; + width: 18% +} +.crm-export-field-selector tbody td:first-child { + width: 28%; + min-width: 230px; +} +.crm-export-field-selector tbody td:first-child > div + div { + margin-left: 17px; +} +.crm-export-field-selector .crm-export-add-field { + width: 16em; +} +.crm-export-ui-save-mapping-dialog .crm-form-block > div { + padding: 5px; +} +.crm-export-ui-save-mapping-dialog .ui-dialog-buttonpane { + position: absolute; + bottom: 20px; + height: 20px; + width: calc(100% - 3em); +} +.crm-export-row-handle { + opacity: .5; +} +.crm-export-field-selector tr:hover .crm-export-row-handle { + opacity: 1; +} diff --git a/ang/exportui/export.html b/ang/exportui/export.html new file mode 100644 index 0000000000..3a1638c33a --- /dev/null +++ b/ang/exportui/export.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + +
+ + +
+ {{ showPreview(row, field) }} +
+ + + + +
diff --git a/ang/exportui/exportField.html b/ang/exportui/exportField.html new file mode 100644 index 0000000000..7ae919749c --- /dev/null +++ b/ang/exportui/exportField.html @@ -0,0 +1,15 @@ +
+ + +
+
+ +
+
+ + + + + + +
diff --git a/ang/exportui/exportSaveMapping.html b/ang/exportui/exportSaveMapping.html new file mode 100644 index 0000000000..39a787db55 --- /dev/null +++ b/ang/exportui/exportSaveMapping.html @@ -0,0 +1,27 @@ +
+
+
+ + +
+
+ + + + {{ model.ts('That name is already taken') }} + +
+
+ + +
+
+
+
+ +
+
+
diff --git a/ang/exportui/exportui.js b/ang/exportui/exportui.js new file mode 100644 index 0000000000..88bb01a268 --- /dev/null +++ b/ang/exportui/exportui.js @@ -0,0 +1,247 @@ +(function(angular, $, _) { + angular.module('exportui', CRM.angRequires('exportui')); + + angular.module('exportui', CRM.angular.modules) + + .controller('ExportUiCtrl', function($scope, $timeout, crmApi, dialogService) { + var ts = $scope.ts = CRM.ts('exportui'), + // Which relationships we've already looked up for the preview + relations = []; + + $scope.option_list = CRM.vars.exportUi.option_list; + $scope.contact_types = CRM.vars.exportUi.contact_types; + $scope.location_type_id = [{id: '', text: ts('Primary')}].concat(CRM.vars.exportUi.location_type_id); + // Map of all fields keyed by name + $scope.fields = _.transform(CRM.vars.exportUi.fields, function(result, category) { + _.each(category.children, function(field) { + result[field.id] = field; + }); + }, {}); + $scope.data = { + preview: CRM.vars.exportUi.preview_data, + contact_type: '', + columns: [] + }; + // For the "add new field" dropdown + $scope.new = {col: ''}; + var contactTypes = _.transform($scope.contact_types, function(result, type) { + result.push(type.id); + _.each(type.children || [], function(subType) { + result.push(subType.id); + }); + }); + var cids = _.filter(_.map(CRM.vars.exportUi.preview_data, 'id')); + + // Get fields for performing the export or saving the field mapping + function getSelectedColumns() { + var map = []; + _.each($scope.data.columns, function(col, no) { + // Make a copy of col without the extra angular props + var item = JSON.parse(angular.toJson(col)); + delete item.select; + delete item.mapping_id; + item.contact_type = $scope.data.contact_type || 'Contact'; + item.column_number = no; + map.push(item); + }); + return map; + } + + // Load a saved field mapping + function loadFieldMap(map) { + $scope.data.columns = []; + var mapContactTypes = []; + _.each(map, function(col) { + if (_.contains(contactTypes, col.contact_type)) { + mapContactTypes.push(col.contact_type); + } + if (col.relationship_type_id && col.relationship_direction) { + col.select = '' + col.relationship_type_id + '_' + col.relationship_direction; + } else { + col.select = col.name; + } + $scope.data.columns.push(col); + }); + // If all the fields are for the same contact type, set it form-wide + if (!$scope.data.contact_type && _.unique(mapContactTypes).length === 1) { + $scope.data.contact_type = mapContactTypes[0]; + } + } + + // Return fields relevant to a contact type + // Filter out non-contact fields (for relationship selectors) + function filterFields(contactType, onlyContact) { + return _.transform(CRM.vars.exportUi.fields, function(result, cat) { + if (!cat.is_contact && onlyContact) { + return; + } + var fields = _.filter(cat.children, function(field) { + return !field.contact_type || !contactType || _.contains(field.contact_type, contactType); + }); + if (fields.length) { + result.push({ + id: cat.id, + text: cat.text, + children: fields + }); + } + }); + } + + $scope.getFields = function() { + return {results: filterFields($scope.data.contact_type)}; + }; + + $scope.getRelatedFields = function(contact_type) { + return function() { + return {results: filterFields(contact_type, true)}; + }; + }; + + $scope.showPreview = function(row, field) { + var key = field.name; + if (field.relationship_type_id && field.relationship_direction) { + fetchRelations(field); + key = '' + field.relationship_type_id + '_' + field.relationship_direction + '_' + key; + } + if (field.location_type_id) { + key += '_' + field.location_type_id + (field.phone_type_id ? '_' + field.phone_type_id : ''); + } + return field.name ? row[key] : ''; + }; + + function fetchRelations(field) { + if (cids.length && !relations[field.relationship_type_id + field.relationship_direction]) { + relations[field.relationship_type_id + field.relationship_direction] = true; + var a = field.relationship_direction[0], + b = field.relationship_direction[2], + params = { + relationship_type_id: field.relationship_type_id, + filters: {is_current: 1}, + "api.Contact.getsingle": {id: '$value.contact_id_' + b} + }; + params['contact_' + a] = {'IN': cids}; + (function (field, params) { + crmApi('Relationship', 'get', params).then(function (data) { + _.each(data.values, function (rel) { + var row = cids.indexOf(rel['contact_id_' + a]); + if (row > -1) { + _.each(rel["api.Contact.getsingle"], function (item, key) { + $scope.data.preview[row][field.relationship_type_id + '_' + field.relationship_direction + '_' + key] = item; + }); + } + }); + }); + })(field, params); + } + } + + $scope.saveMappingDialog = function() { + var options = CRM.utils.adjustDialogDefaults({ + width: '40%', + height: 300, + autoOpen: false, + title: ts('Save Fields') + }); + var mappingNames = _.transform(CRM.vars.exportUi.mapping_names, function(result, n, key) { + result[key] = n.toLowerCase(); + }); + var model = { + ts: ts, + saving: false, + overwrite: CRM.vars.exportUi.mapping_id ? '1' : '0', + mapping_id: CRM.vars.exportUi.mapping_id, + mapping_type_id: CRM.vars.exportUi.mapping_type_id, + mapping_names: CRM.vars.exportUi.mapping_names, + new_name: CRM.vars.exportUi.mapping_id ? CRM.vars.exportUi.mapping_names[CRM.vars.exportUi.mapping_id] : '', + description: CRM.vars.exportUi.mapping_description, + nameIsUnique: function() { + return !_.contains(mappingNames, this.new_name.toLowerCase()) || (this.overwrite === '1' && this.new_name.toLowerCase() === this.mapping_names[this.mapping_id].toLowerCase()); + }, + saveMapping: function() { + this.saving = true; + var mapping = { + id: this.overwrite === '1' ? this.mapping_id : null, + mapping_type_id: this.mapping_type_id, + name: this.new_name, + description: this.description, + sequential: 1 + }, + mappingFields = getSelectedColumns(); + if (!mapping.id) { + _.each(mappingFields, function(field) { + delete field.id; + }); + } + mapping['api.MappingField.replace'] = {values: mappingFields}; + crmApi('Mapping', 'create', mapping).then(function(result) { + CRM.vars.exportUi.mapping_id = result.id; + CRM.vars.exportUi.mapping_description = mapping.description; + CRM.vars.exportUi.mapping_names[result.id] = mapping.name; + // Call loadFieldMap to update field ids in $scope.data.columns + loadFieldMap(result.values[0]['api.MappingField.replace'].values); + dialogService.close('exportSaveMapping'); + }); + } + }; + dialogService.open('exportSaveMapping', '~/exportui/exportSaveMapping.html', model, options); + }; + + // Load saved mapping + if ($('input[name=export_field_map]').val()) { + loadFieldMap(JSON.parse($('input[name=export_field_map]').val())); + } + + // Add new col + $scope.$watch('new.col', function(val) { + var field = val; + $timeout(function() { + if (field) { + $scope.data.columns.push({ + select: field, + name: '', + location_type_id: null, + phone_type_id: null, + website_type_id: null, + im_provider_id: null, + relationship_type_id: null, + relationship_direction: null + }); + $scope.new.col = ''; + } + }); + }); + + // When adding/removing columns + $scope.$watch('data.columns', function(values) { + _.each(values, function(col, index) { + // Remove empty values + if (!col.select) { + $scope.data.columns.splice(index, 1); + } else { + // Format item + var selection = $scope.fields[col.select]; + if (selection.relationship_type_id) { + col.relationship_type_id = selection.relationship_type_id; + col.relationship_direction = col.select.slice(col.select.indexOf('_')+1); + } else { + col.name = col.select; + col.relationship_direction = col.relationship_type_id = null; + } + var field = col.name ? $scope.fields[col.name] : {}; + col.location_type_id = field.has_location ? col.location_type_id || '' : null; + _.each($scope.option_list, function(options, list) { + col[list] = (col.location_type_id || !field.has_location) && field.option_list === list ? col[list] || options[0].id : null; + }); + } + }); + // Store data in a quickform hidden field + var selectedColumns = getSelectedColumns(); + $('input[name=export_field_map]').val(JSON.stringify(selectedColumns)); + + // Hide submit button when no fields selected + $('.crm-button_qf_Map_next').toggle(!!selectedColumns.length); + }, true); + }); + +})(angular, CRM.$, CRM._); diff --git a/extension-compatibility.json b/extension-compatibility.json index 60be476584..b7b4031ae3 100644 --- a/extension-compatibility.json +++ b/extension-compatibility.json @@ -1,4 +1,9 @@ { + "org.civicrm.exportui": { + "obsolete": "5.23", + "disable": true, + "uninstall": true + }, "org.civicrm.api4": { "obsolete": "5.19", "force-uninstall": true diff --git a/templates/CRM/Export/Form/Map.tpl b/templates/CRM/Export/Form/Map.tpl index f3964cfb22..b5746306ff 100644 --- a/templates/CRM/Export/Form/Map.tpl +++ b/templates/CRM/Export/Form/Map.tpl @@ -23,11 +23,12 @@ {* WizardHeader.tpl provides visual display of steps thru the wizard as well as title for current step *} {include file="CRM/common/WizardHeader.tpl"} -
{include file="CRM/common/formButtons.tpl" location="top"}
+
{include file="CRM/common/formButtons.tpl" location="top"}
-{* Table for mapping data to CRM fields *} -{include file="CRM/Export/Form/table.tpl"} +
+
+
-
{include file="CRM/common/formButtons.tpl" location="bottom"}
-{$initHideBoxes} +
{include file="CRM/common/formButtons.tpl" location="bottom"}
+ {$initHideBoxes} diff --git a/templates/CRM/Export/Form/table.tpl b/templates/CRM/Export/Form/table.tpl deleted file mode 100644 index dfddabfcba..0000000000 --- a/templates/CRM/Export/Form/table.tpl +++ /dev/null @@ -1,76 +0,0 @@ -{* - +--------------------------------------------------------------------+ - | Copyright CiviCRM LLC. All rights reserved. | - | | - | This work is published under the GNU AGPLv3 license with some | - | permitted exceptions and without any warranty. For full license | - | and copyright information, see https://civicrm.org/licensing | - +--------------------------------------------------------------------+ -*} -{* Export Wizard - Data Mapping table used by MapFields.tpl and Preview.tpl *} -
- {strip} - - {if $loadedMapping} - - {/if} - - - - {*section name=cols loop=$columnCount*} - {section name=cols loop=$columnCount.1} - {assign var="i" value=$smarty.section.cols.index} - - - - {/section} - - - - -
{ts 1=$savedName}Using Field Mapping: %1{/ts}
{ts}Fields to Include in Export File{/ts}
- {$form.mapper.1[$i].html} -
- {$form.addMore.1.html} -
- {/strip} - - -
- {if $loadedMapping} - {$form.updateMapping.html}{$form.updateMapping.label}    - {/if} - {$form.saveMapping.html}{$form.saveMapping.label} -
- - - -
{$form.saveMappingName.label}{$form.saveMappingName.html}
{$form.saveMappingDesc.label}{$form.saveMappingDesc.html}
-
- - - -
- -
-- 2.25.1