Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SearchKit - Add 'whole row' and 'add row' editable features #31583

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CRM/Utils/String.php
Original file line number Diff line number Diff line change
Expand Up @@ -1112,4 +1112,21 @@ public static function getSquareTokens(string $raw): array {
return $tokens;
}

public static function isQuotedString($value): bool {
return is_string($value) && strlen($value) > 1 && $value[0] === $value[-1] && in_array($value[0], ['"', "'"]);
}

public static function unquoteString(string $string): string {
// Strip the outer quotes if the string starts and ends with the same quote type
if (self::isQuotedString($string)) {
$string = substr($string, 1, -1);

// Replace escaped quotes with unescaped quotes, avoiding escaped backslashes
$string = preg_replace('/(?<!\\\\)\\\\\\"/', '"', $string);
$string = preg_replace('/(?<!\\\\)\\\\\\\'/', "'", $string);
}

return $string;
}

}
3 changes: 3 additions & 0 deletions ext/civicrm_admin_ui/ang/afsearchCustomFieldOptions.aff.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div af-fieldset="">
<crm-search-display-table search-name="Administer_Custom_Field_Options" display-name="Administer_Custom_Field_Options" filters="{option_group_id: routeParams.option_group_id}"></crm-search-display-table>
</div>
9 changes: 9 additions & 0 deletions ext/civicrm_admin_ui/ang/afsearchCustomFieldOptions.aff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
use CRM_CivicrmAdminUi_ExtensionUtil as E;

return [
'type' => 'search',
'title' => E::ts('Custom Field Options'),
'icon' => 'fa-list-ol',
'server_route' => 'civicrm/admin/custom/group/field/options',
];
37 changes: 37 additions & 0 deletions ext/civicrm_admin_ui/civicrm_admin_ui.civix.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,47 @@ public static function findClass($suffix) {
return self::CLASS_PREFIX . '_' . str_replace('\\', '_', $suffix);
}

/**
* @return \CiviMix\Schema\SchemaHelperInterface
*/
public static function schema() {
if (!isset($GLOBALS['CiviMixSchema'])) {
pathload()->loadPackage('civimix-schema@5', TRUE);
}
return $GLOBALS['CiviMixSchema']->getHelper(static::LONG_NAME);
}

}

use CRM_CivicrmAdminUi_ExtensionUtil as E;

($GLOBALS['_PathLoad'][0] ?? require __DIR__ . '/mixin/lib/pathload-0.php');
pathload()->addSearchDir(__DIR__ . '/mixin/lib');
spl_autoload_register('_civicrm_admin_ui_civix_class_loader', TRUE, TRUE);

function _civicrm_admin_ui_civix_class_loader($class) {
if ($class === 'CRM_CivicrmAdminUi_DAO_Base') {
if (version_compare(CRM_Utils_System::version(), '5.74.beta', '>=')) {
class_alias('CRM_Core_DAO_Base', 'CRM_CivicrmAdminUi_DAO_Base');
// ^^ Materialize concrete names -- encourage IDE's to pick up on this association.
}
else {
$realClass = 'CiviMix\\Schema\\CivicrmAdminUi\\DAO';
class_alias($realClass, $class);
// ^^ Abstract names -- discourage IDE's from picking up on this association.
}
return;
}

// This allows us to tap-in to the installation process (without incurring real file-reads on typical requests).
if (strpos($class, 'CiviMix\\Schema\\CivicrmAdminUi\\') === 0) {
// civimix-schema@5 is designed for backported use in download/activation workflows,
// where new revisions may become dynamically available.
pathload()->loadPackage('civimix-schema@5', TRUE);
CiviMix\Schema\loadClass($class);
}
}

/**
* (Delegated) Implements hook_civicrm_config().
*
Expand Down
4 changes: 2 additions & 2 deletions ext/civicrm_admin_ui/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
<civix>
<namespace>CRM/CivicrmAdminUi</namespace>
<angularModule>crmCivicrmAdminUi</angularModule>
<format>23.02.1</format>
<format>24.09.1</format>
</civix>
<mixins>
<mixin>[email protected]</mixin>
<mixin>[email protected]</mixin>
</mixins>
<upgrader>CRM_CivicrmAdminUi_Upgrader</upgrader>
<upgrader>CiviMix\Schema\CivicrmAdminUi\AutomaticUpgrader</upgrader>
</extension>
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php
use CRM_CivicrmAdminUi_ExtensionUtil as E;

return [
[
'name' => 'SavedSearch_Administer_Custom_Field_Options',
'entity' => 'SavedSearch',
'cleanup' => 'unused',
'update' => 'unmodified',
'params' => [
'version' => 4,
'values' => [
'name' => 'Administer_Custom_Field_Options',
'label' => E::ts('Administer Custom Field Options'),
'api_entity' => 'OptionValue',
'api_params' => [
'version' => 4,
'select' => [
'label',
'value',
'description',
'option_group_id:label',
],
'orderBy' => [],
'where' => [],
'groupBy' => [],
'join' => [],
'having' => [],
],
],
'match' => ['name'],
],
],
[
'name' => 'SavedSearch_Administer_Custom_Field_Options_SearchDisplay_Administer_Custom_Field_Options',
'entity' => 'SearchDisplay',
'cleanup' => 'unused',
'update' => 'unmodified',
'params' => [
'version' => 4,
'values' => [
'name' => 'Administer_Custom_Field_Options',
'label' => E::ts('Administer Custom Field Options'),
'saved_search_id.name' => 'Administer_Custom_Field_Options',
'type' => 'table',
'settings' => [
'description' => E::ts(''),
'sort' => [],
'limit' => 50,
'pager' => [
'show_count' => TRUE,
'expose_limit' => TRUE,
'hide_single' => TRUE,
],
'placeholder' => 5,
'cssRules' => [
[
'disabled',
'is_active',
'=',
FALSE,
],
],
'columns' => [
[
'type' => 'field',
'key' => 'label',
'dataType' => 'String',
'label' => E::ts('Option Label'),
'sortable' => TRUE,
'editable' => TRUE,
],
[
'type' => 'field',
'key' => 'value',
'dataType' => 'String',
'label' => E::ts('Option Value'),
'sortable' => TRUE,
],
[
'type' => 'field',
'key' => 'description',
'dataType' => 'Text',
'label' => E::ts('Option Description'),
'sortable' => TRUE,
'show_linebreaks' => FALSE,
'editable' => TRUE,
],
[
'text' => '',
'style' => 'default',
'size' => 'btn-xs',
'icon' => 'fa-bars',
'links' => [
[
'entity' => 'OptionValue',
'action' => 'update',
'join' => '',
'target' => 'crm-popup',
'icon' => 'fa-pencil',
'text' => E::ts('Edit'),
'style' => 'default',
'path' => '',
'condition' => [],
],
[
'task' => 'enable',
'entity' => 'OptionValue',
'target' => 'crm-popup',
'icon' => 'fa-toggle-on',
'text' => E::ts('Enable'),
'style' => 'default',
'condition' => [],
],
[
'task' => 'disable',
'entity' => 'OptionValue',
'target' => 'crm-popup',
'icon' => 'fa-toggle-off',
'text' => E::ts('Disable'),
'style' => 'default',
'condition' => [],
],
[
'entity' => 'OptionValue',
'action' => 'delete',
'join' => '',
'target' => 'crm-popup',
'icon' => 'fa-trash',
'text' => E::ts('Delete'),
'style' => 'danger',
'path' => '',
'condition' => [],
],
],
'type' => 'menu',
'alignment' => 'text-right',
],
],
'actions' => FALSE,
'editableRow' => [
'create' => TRUE,
'createLabel' => E::ts('Add Option'),
],
'classes' => ['table', 'table-striped'],
'draggable' => 'weight',
],
],
'match' => [
'saved_search_id',
'name',
],
],
],
];
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@
'icon' => 'fa-list-ol',
'text' => E::ts('Multiple Choice Options'),
'style' => 'default',
'path' => 'civicrm/admin/custom/group/field/option?reset=1&action=browse&gid=[custom_group_id]&fid=[id]',
'path' => 'civicrm/admin/custom/group/field/options#?option_group_id=[option_group_id]',
'condition' => [
'option_group_id:label',
'option_group_id:name',
'IS NOT EMPTY',
],
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ protected function formatResult(iterable $result): array {
$data[$key] = $this->getValue($key, $record, $index);
}
foreach ($this->display['settings']['columns'] as $column) {
$columns[] = $this->formatColumn($column, $data);
$columns[] = $this->formatColumn($column, $data, $this->display['settings']);
}
$row = [
'data' => $data,
Expand Down Expand Up @@ -232,9 +232,10 @@ private function generateFileUrl($fileID) {
/**
* @param array $column
* @param array $data
* @param array $settings
* @return array{val: mixed, links: array, edit: array, label: string, title: string, image: array, cssClass: string}
*/
private function formatColumn($column, $data) {
private function formatColumn(array $column, array $data, array $settings) {
$column += ['rewrite' => NULL, 'label' => NULL, 'key' => ''];
$out = [];
switch ($column['type']) {
Expand Down Expand Up @@ -262,11 +263,11 @@ private function formatColumn($column, $data) {
$out['links'] = $links;
}
}
elseif (!empty($column['editable']) && !$column['rewrite']) {
elseif (!empty($column['editable']) && !$column['rewrite'] && empty($settings['editableRow']['disable'])) {
$edit = $this->formatEditableColumn($column, $data);
if ($edit) {
// When internally processing an inline-edit, get all metadata
if (isset($this->colKey) && $this->colKey === $column['key']) {
if (isset($this->rowKey) && isset($this->values) && array_key_exists($column['key'], $this->values)) {
$out['edit'] = $edit;
}
// Otherwise, the client only needs a boolean
Expand Down Expand Up @@ -1839,4 +1840,34 @@ protected function getIdKeyName(?string $entityName) {
return CoreUtil::getIdFieldName($entityName);
}

/**
* Get data from the where/having clauses, useful for inferring values to create a new entity
*
* If $this->applyFilters has already run, it will include data from filters
*
* @return array
* @throws \CRM_Core_Exception
*/
public function getQueryData(): array {
// First pass: gather raw data from the where & having clauses
$data = [];
foreach (array_merge($this->_apiParams['where'], $this->_apiParams['having'] ?? []) as $clause) {
if ($clause[1] === '=' || $clause[1] === 'IN') {
$data[$clause[0]] = $clause[2];
}
}
// Second pass: format values (because data from first pass could be useful to FormattingUtil)
foreach ($this->_apiParams['where'] as $clause) {
if ($clause[1] === '=' || $clause[1] === 'IN') {
[$fieldPath] = explode(':', $clause[0]);
$fieldSpec = $this->getField($fieldPath);
$data[$fieldPath] = $clause[2];
if ($fieldSpec) {
FormattingUtil::formatInputValue($data[$fieldPath], $clause[0], $fieldSpec, $data, $clause[1]);
}
}
}
return $data;
}

}
Loading