diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
index 3972c0a02ded..c089bc360cdc 100644
--- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
+++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
@@ -706,7 +706,7 @@ private function getUrl(string $path, $query = NULL) {
/**
* @param array $column
* @param array $data
- * @return array{entity: string, action: string, input_type: string, data_type: string, options: bool, serialize: bool, nullable: bool, fk_entity: string, value_key: string, record: array, value: mixed}|null
+ * @return array{entity: string, action: string, input_type: string, data_type: string, options: bool, serialize: bool, nullable: bool, fk_entity: string, value_key: string, record: array, value_path: string}|null
*/
private function formatEditableColumn($column, $data) {
$editable = $this->getEditableInfo($column['key']);
@@ -715,7 +715,6 @@ private function formatEditableColumn($column, $data) {
if (!empty($data[$editable['id_path']])) {
$editable['action'] = 'update';
$editable['record'][$editable['id_key']] = $data[$editable['id_path']];
- $editable['value'] = $data[$editable['value_path']];
// Ensure field is appropriate to this entity sub-type
$field = $this->getField($column['key']);
$entityValues = FormattingUtil::filterByPath($data, $editable['id_path'], $editable['id_key']);
@@ -726,7 +725,6 @@ private function formatEditableColumn($column, $data) {
// Generate params to create new record, if applicable
elseif ($editable['explicit_join'] && !$this->getJoin($editable['explicit_join'])['bridge']) {
$editable['action'] = 'create';
- $editable['value'] = NULL;
$editable['nullable'] = FALSE;
// Get values for creation from the join clause
$join = $this->getQuery()->getExplicitJoin($editable['explicit_join']);
@@ -776,8 +774,14 @@ private function formatEditableColumn($column, $data) {
'values' => $entityValues,
], 0)['access'];
if ($access) {
+ // Add currency formatting info
+ if ($editable['data_type'] === 'Money') {
+ $currencyField = $this->getCurrencyField($column['key']);
+ $currency = is_string($data[$currencyField] ?? NULL) ? $data[$currencyField] : NULL;
+ $editable['currency_format'] = \Civi::format()->money(1234.56, $currency);
+ }
// Remove info that's for internal use only
- \CRM_Utils_Array::remove($editable, 'id_key', 'id_path', 'value_path', 'explicit_join', 'grouping_fields');
+ \CRM_Utils_Array::remove($editable, 'id_key', 'id_path', 'explicit_join', 'grouping_fields');
return $editable;
}
}
diff --git a/ext/search_kit/ang/crmSearchDisplay/colType/field.html b/ext/search_kit/ang/crmSearchDisplay/colType/field.html
index 06678c917ac8..ceb1664696b9 100644
--- a/ext/search_kit/ang/crmSearchDisplay/colType/field.html
+++ b/ext/search_kit/ang/crmSearchDisplay/colType/field.html
@@ -1,10 +1,10 @@
-
-
+
+
{{:: $ctrl.formatFieldValue(colData) }}
-
+
diff --git a/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js b/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
index cedb4db87d53..3a2488f7cf3c 100644
--- a/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
+++ b/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
@@ -8,8 +8,7 @@
bindings: {
row: '<',
col: '<',
- cancel: '&',
- doSave: '&'
+ cancel: '&'
},
templateUrl: '~/crmSearchDisplay/crmSearchDisplayEditable.html',
controller: function($scope, $element, crmApi4) {
@@ -19,8 +18,8 @@
this.$onInit = function() {
col = this.col;
- this.value = _.cloneDeep(col.edit.value);
- initialValue = _.cloneDeep(col.edit.value);
+ this.value = _.cloneDeep(this.row.data[col.edit.value_path]);
+ initialValue = _.cloneDeep(this.row.data[col.edit.value_path]);
this.field = {
data_type: col.edit.data_type,
@@ -50,16 +49,52 @@
};
this.save = function() {
- if (ctrl.value === initialValue) {
- ctrl.cancel();
- return;
+ const value = formatDataType(ctrl.value);
+ if (value !== initialValue) {
+ col.edit.record[col.edit.value_key] = value;
+ CRM.status({}, crmApi4(col.edit.entity, col.edit.action, {values: col.edit.record}));
+ ctrl.row.data[col.edit.value_path] = value;
+ col.val = formatDisplayValue(value);
}
- var record = _.cloneDeep(col.edit.record);
- record[col.edit.value_key] = ctrl.value;
- $('input', $element).attr('disabled', true);
- ctrl.doSave({apiCall: [col.edit.entity, col.edit.action, {values: record}]});
+ ctrl.cancel();
};
+ function formatDataType(val) {
+ if (_.isArray(val)) {
+ const formatted = angular.copy(val);
+ formatted.forEach((v, i) => formatted[i] = formatDataType(v));
+ return formatted;
+ }
+ if (ctrl.field.data_type === 'Integer') {
+ return +val;
+ }
+ return val;
+ }
+
+ function formatDisplayValue(val) {
+ let displayValue = angular.copy(val);
+ if (_.isArray(displayValue)) {
+ displayValue.forEach((v, i) => displayValue[i] = formatDisplayValue(v));
+ return displayValue;
+ }
+ if (ctrl.field.options) {
+ ctrl.field.options.forEach((option) => {
+ if (('' + option.id) === ('' + val)) {
+ displayValue = option.label;
+ }
+ });
+ } else if (ctrl.field.data_type === 'Boolean' && val === true) {
+ displayValue = ts('Yes');
+ } else if (ctrl.field.data_type === 'Boolean' && val === false) {
+ displayValue = ts('No');
+ } else if (ctrl.field.data_type === 'Date' || ctrl.field.data_type === 'Timestamp') {
+ displayValue = CRM.utils.formatDate(val, null, ctrl.field.data_type === 'Timestamp');
+ } else if (ctrl.field.data_type === 'Money') {
+ displayValue = CRM.formatMoney(displayValue, false, col.edit.currency_format);
+ }
+ return displayValue;
+ }
+
function loadOptions() {
var cacheKey = col.edit.entity + ' ' + ctrl.field.name;
if (optionsCache[cacheKey]) {
diff --git a/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js b/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
index 617a8a841adc..0cf2add6adcb 100644
--- a/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
+++ b/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
@@ -201,6 +201,9 @@
},
formatFieldValue: function(colData) {
return angular.isArray(colData.val) ? colData.val.join(', ') : colData.val;
+ },
+ isEditing: function(rowIndex, colIndex) {
+ return this.editing && this.editing[0] === rowIndex && this.editing[1] === colIndex;
}
};
});
diff --git a/ext/search_kit/css/crmSearchTasks.css b/ext/search_kit/css/crmSearchTasks.css
index d70be29ffffd..f6b6f6c795e2 100644
--- a/ext/search_kit/css/crmSearchTasks.css
+++ b/ext/search_kit/css/crmSearchTasks.css
@@ -14,10 +14,6 @@
position: relative;
}
-.crm-search-display crm-search-display-editable + span.crm-editable-disabled {
- display: none !important;
-}
-
.crm-search-display .crm-search-display-editable-buttons {
position: absolute;
bottom: -24px;
diff --git a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php
index 2790bf143d8d..18b882714c18 100644
--- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php
+++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php
@@ -551,7 +551,7 @@ public function testInPlaceEditAndCreate() {
$this->assertEquals('String', $result[0]['columns'][0]['edit']['data_type']);
$this->assertEquals('first_name', $result[0]['columns'][0]['edit']['value_key']);
$this->assertEquals('update', $result[0]['columns'][0]['edit']['action']);
- $this->assertEquals('One', $result[0]['columns'][0]['edit']['value']);
+ $this->assertEquals('One', $result[0]['data'][$result[0]['columns'][0]['edit']['value_path']]);
// Contact 1 email can be updated
$this->assertEquals('testmail@unit.test', $result[0]['columns'][1]['val']);
@@ -561,7 +561,7 @@ public function testInPlaceEditAndCreate() {
$this->assertEquals('String', $result[0]['columns'][1]['edit']['data_type']);
$this->assertEquals('email', $result[0]['columns'][1]['edit']['value_key']);
$this->assertEquals('update', $result[0]['columns'][1]['edit']['action']);
- $this->assertEquals('testmail@unit.test', $result[0]['columns'][1]['edit']['value']);
+ $this->assertEquals('testmail@unit.test', $result[0]['data'][$result[0]['columns'][1]['edit']['value_path']]);
// Contact 1 - new phone can be created
$this->assertNull($result[0]['columns'][2]['val']);
@@ -571,7 +571,7 @@ public function testInPlaceEditAndCreate() {
$this->assertEquals('String', $result[0]['columns'][2]['edit']['data_type']);
$this->assertEquals('phone', $result[0]['columns'][2]['edit']['value_key']);
$this->assertEquals('create', $result[0]['columns'][2]['edit']['action']);
- $this->assertNull($result[0]['columns'][2]['edit']['value']);
+ $this->assertEquals('Contact_Phone_contact_id_01.phone', $result[0]['columns'][2]['edit']['value_path']);
// Contact 2 first name can be added
$this->assertNull($result[1]['columns'][0]['val']);
@@ -581,7 +581,7 @@ public function testInPlaceEditAndCreate() {
$this->assertEquals('String', $result[1]['columns'][0]['edit']['data_type']);
$this->assertEquals('first_name', $result[1]['columns'][0]['edit']['value_key']);
$this->assertEquals('update', $result[1]['columns'][0]['edit']['action']);
- $this->assertNull($result[1]['columns'][0]['edit']['value']);
+ $this->assertEquals('first_name', $result[1]['columns'][0]['edit']['value_path']);
// Contact 2 - new email can be created
$this->assertNull($result[1]['columns'][1]['val']);
@@ -591,7 +591,7 @@ public function testInPlaceEditAndCreate() {
$this->assertEquals('String', $result[1]['columns'][1]['edit']['data_type']);
$this->assertEquals('email', $result[1]['columns'][1]['edit']['value_key']);
$this->assertEquals('create', $result[1]['columns'][1]['edit']['action']);
- $this->assertNull($result[1]['columns'][1]['edit']['value']);
+ $this->assertEquals('Contact_Email_contact_id_01.email', $result[1]['columns'][1]['edit']['value_path']);
// Contact 2 phone can be updated
$this->assertEquals('123456', $result[1]['columns'][2]['val']);
@@ -601,7 +601,7 @@ public function testInPlaceEditAndCreate() {
$this->assertEquals('String', $result[1]['columns'][2]['edit']['data_type']);
$this->assertEquals('phone', $result[1]['columns'][2]['edit']['value_key']);
$this->assertEquals('update', $result[1]['columns'][2]['edit']['action']);
- $this->assertEquals('123456', $result[1]['columns'][2]['edit']['value']);
+ $this->assertEquals('123456', $result[1]['data'][$result[0]['columns'][2]['edit']['value_path']]);
}
/**
@@ -1497,7 +1497,7 @@ public function testEditableContactFields() {
'value_key' => 'first_name',
'record' => ['id' => $contact[0]['id']],
'action' => 'update',
- 'value' => 'One',
+ 'value_path' => 'first_name',
];
// Ensure first_name is editable but not organization_name or household_name
$this->assertEquals($expectedFirstNameEdit, $result[0]['columns'][0]['edit']);
@@ -1506,7 +1506,6 @@ public function testEditableContactFields() {
// Second Individual
$expectedFirstNameEdit['record']['id'] = $contact[1]['id'];
- $expectedFirstNameEdit['value'] = NULL;
$this->assertEquals($expectedFirstNameEdit, $result[1]['columns'][0]['edit']);
$this->assertTrue(!isset($result[1]['columns'][1]['edit']));
$this->assertTrue(!isset($result[1]['columns'][2]['edit']));
@@ -1514,6 +1513,7 @@ public function testEditableContactFields() {
// Third contact: Organization
$expectedFirstNameEdit['record']['id'] = $contact[2]['id'];
$expectedFirstNameEdit['value_key'] = 'organization_name';
+ $expectedFirstNameEdit['value_path'] = 'organization_name';
$this->assertTrue(!isset($result[2]['columns'][0]['edit']));
$this->assertEquals($expectedFirstNameEdit, $result[2]['columns'][1]['edit']);
$this->assertTrue(!isset($result[2]['columns'][2]['edit']));
@@ -1521,6 +1521,7 @@ public function testEditableContactFields() {
// Third contact: Household
$expectedFirstNameEdit['record']['id'] = $contact[3]['id'];
$expectedFirstNameEdit['value_key'] = 'household_name';
+ $expectedFirstNameEdit['value_path'] = 'household_name';
$this->assertTrue(!isset($result[3]['columns'][0]['edit']));
$this->assertTrue(!isset($result[3]['columns'][1]['edit']));
$this->assertEquals($expectedFirstNameEdit, $result[3]['columns'][2]['edit']);
diff --git a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunWithCustomFieldTest.php b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunWithCustomFieldTest.php
index 5096e3f03cfa..2cf32ba633b5 100644
--- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunWithCustomFieldTest.php
+++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunWithCustomFieldTest.php
@@ -360,9 +360,9 @@ public function testEditableCustomFields() {
'value_key' => 'meeting_phone.sub_field',
'record' => ['id' => $activity[0]['id']],
'action' => 'update',
- 'value' => 'Abc',
+ 'value_path' => 'meeting_phone.sub_field',
];
- $expectedSubjectEdit = ['value_key' => 'subject', 'value' => $subject] + $expectedCustomFieldEdit;
+ $expectedSubjectEdit = ['value_key' => 'subject', 'value_path' => 'subject'] + $expectedCustomFieldEdit;
// First Activity
$this->assertEquals($expectedSubjectEdit, $result[0]['columns'][0]['edit']);
@@ -372,7 +372,6 @@ public function testEditableCustomFields() {
// Second Activity
$expectedSubjectEdit['record']['id'] = $activity[1]['id'];
$expectedCustomFieldEdit['record']['id'] = $activity[1]['id'];
- $expectedCustomFieldEdit['value'] = NULL;
$this->assertEquals($expectedSubjectEdit, $result[1]['columns'][0]['edit']);
$this->assertEquals($expectedCustomFieldEdit, $result[1]['columns'][1]['edit']);
$this->assertEquals($activityTypes['Phone Call'], $result[1]['data']['activity_type_id']);