GUI: Entity config
authorColeman Watts <coleman@civicrm.org>
Tue, 12 Nov 2019 03:20:12 +0000 (22:20 -0500)
committerCiviCRM <info@civicrm.org>
Wed, 16 Sep 2020 02:13:20 +0000 (19:13 -0700)
ext/afform/gui/afform_gui.php
ext/afform/gui/ang/afGuiEditor.js
ext/afform/gui/ang/afGuiEditor/entity.html
ext/afform/gui/ang/afGuiEditor/entityConfig/Activity.html [new file with mode: 0644]
ext/afform/gui/ang/afGuiEditor/entityConfig/Contact.html [new file with mode: 0644]
ext/afform/gui/ang/afGuiEditor/entityConfig/Generic.html [new file with mode: 0644]
ext/afform/gui/ang/afGuiEditor/entityDefaults/Activity.json [new file with mode: 0644]
ext/afform/gui/ang/afGuiEditor/entityDefaults/Contact.json [new file with mode: 0644]

index 5aef321d4002a4cd6b6984830f1b9e8301953e1c..1994e9be980ee3ee771618f322b564c83ddf8ee3 100644 (file)
@@ -160,44 +160,41 @@ function afform_gui_civicrm_buildAsset($asset, $params, &$mimeType, &$content) {
     return;
   }
 
-  // Things that can't be handled by afform. TODO: Need a better way to do this. Maybe add core metadata about what each entity is for, and filter on that.
-  $entityBlacklist = [
-    'ACL',
-    'ActionSchedule',
-    'ActivityContact',
-    'Afform%',
-    'CaseContact',
-    'EntityTag',
-    'GroupContact',
-    'GroupNesting',
-    'GroupOrganization',
-    'Setting',
-    'System',
-    'UF%',
-  ];
-  $entityApi = Civi\Api4\Entity::get()
-    ->setCheckPermissions(FALSE)
-    ->setSelect(['name', 'description']);
-  foreach ($entityBlacklist as $nono) {
-    $entityApi->addWhere('name', 'NOT LIKE', $nono);
+  $entityWhitelist = $data = [];
+
+  // First scan the entityDefaults directory for our list of supported entities
+  // FIXME: Need a way to load this from other extensions too
+  foreach (glob(__DIR__ . '/ang/afGuiEditor/entityDefaults/*.json') as $file) {
+    $matches = [];
+    preg_match('/([-a-z_A-Z0-9]*).json/', $file, $matches);
+    $entityWhitelist[] = $entity = $matches[1];
+    // No json_decode, the files are not strict json and will go through angular.$parse clientside
+    $data['defaults'][$entity] = trim(CRM_Utils_JS::stripComments(file_get_contents($file)));
   }
 
-  $contactFields = Civi\Api4\Contact::getFields()
+  $data['entities'] = (array) Civi\Api4\Entity::get()
     ->setCheckPermissions(FALSE)
-    ->setIncludeCustom(TRUE)
-    ->setLoadOptions(TRUE)
-    ->setAction('create')
-    ->setSelect(['name', 'title', 'input_type', 'input_attrs', 'options'])
+    ->setSelect(['name', 'description'])
+    ->addWhere('name', 'IN', $entityWhitelist)
     ->execute();
 
-  $contactSettings = [
-    'data' => [],
-  ];
+  foreach ($entityWhitelist as $entityName) {
+    $api = 'Civi\\Api4\\' . $entityName;
+    $data['fields'][$entityName] = (array) $api::getFields()
+      ->setCheckPermissions(FALSE)
+      ->setIncludeCustom(TRUE)
+      ->setLoadOptions(TRUE)
+      ->setAction('create')
+      ->setSelect(['name', 'title', 'input_type', 'input_attrs', 'options'])
+      ->addWhere('input_type', 'IS NOT NULL')
+      ->execute()
+      ->indexBy('name');
+  }
+
+  // Now adjust the field metadata
+  // FIXME: This should probably be a callback event or something to allow extensions to tweak the metadata for their entities
+  $data['fields']['Contact']['contact_type']['required_data'] = TRUE;
 
   $mimeType = 'text/javascript';
-  $content = "CRM.afformAdminData={";
-  $content .= 'entities:' . json_encode((array) $entityApi->execute(), JSON_UNESCAPED_SLASHES) . ',';
-  $content .= 'fields:' . json_encode(['Contact' => (array) $contactFields], JSON_UNESCAPED_SLASHES) . ',';
-  $content .= 'settings:' . json_encode(['Contact' => $contactSettings], JSON_UNESCAPED_SLASHES);
-  $content .= '}';
+  $content = "CRM.afformAdminData=" . json_encode($data, JSON_UNESCAPED_SLASHES) . ';';
 }
index eb9009c811e51c02abedaf171991298dd36b69ed..7322a8367d7759903959424fd29f201a906bac7f 100644 (file)
           while (_.contains(existingEntitiesofThisType, entityType + num)) {
             num++;
           }
-          $scope.entities[entityType + num] = {
+          $scope.entities[entityType + num] = _.assign($parse(this.meta.defaults[entityType])($scope), {
             '#tag': 'af-entity',
             type: entityType,
             name: entityType + num,
             label: entityType + ' ' + num
-          };
+          });
           $scope.layout['#children'].unshift($scope.entities[entityType + num]);
           $scope.layout['#children'].push({
             '#tag': 'fieldset',
         };
 
         this.getField = function(entityType, fieldName) {
-          return _.filter($scope.meta.fields[entityType], {name: fieldName})[0];
+          return $scope.meta.fields[entityType][fieldName];
         };
 
         this.getEntity = function(entityName) {
             });
         };
 
+        $scope.$watch('afform.title', function(newTitle, oldTitle) {
+          if (typeof oldTitle === 'string') {
+            _.each($scope.entities, function(entity) {
+              if (entity.data && entity.data.source === oldTitle) {
+                entity.data.source = newTitle;
+              }
+            });
+          }
+        });
+
         // Parse strings of javascript that php couldn't interpret
         function evaluate(collection) {
           _.each(collection, function(item) {
         };
 
         $scope.setStyle = function(val) {
-          $scope.block.modifyClasses($scope.node, _.keys($scope.styles), val);
+          $scope.block.modifyClasses($scope.node, _.keys($scope.styles), ['btn', val]);
         };
 
         $scope.pickIcon = function() {
index 3359340867e0da1864c9acc952888fe166d2e621..6c86b85927e02ee9352159a8aec604ae700651ca 100644 (file)
@@ -4,7 +4,7 @@
     <div class="form-inline" ng-if="entity.data" ng-repeat="(fieldName, value) in entity.data">
       <label>{{ editor.getField(entity.type, fieldName).title }}:</label><br />
       <input class="form-control" af-gui-field-value="editor.getField(entity.type, fieldName)" ng-model="entity.data[fieldName]" />
-      <a href class="" ng-click="removeValue(entity, fieldName)">
+      <a href class="" ng-click="removeValue(entity, fieldName)" ng-if="!editor.getField(entity.type, fieldName).required_data">
         <i class="crm-i fa-times"></i>
       </a>
     </div>
@@ -36,4 +36,5 @@
 
 <fieldset>
   <legend>{{ ts('Options') }}</legend>
+  <div ng-include="'~/afGuiEditor/entityConfig/' + entity.type + '.html'"></div>
 </fieldset>
diff --git a/ext/afform/gui/ang/afGuiEditor/entityConfig/Activity.html b/ext/afform/gui/ang/afGuiEditor/entityConfig/Activity.html
new file mode 100644 (file)
index 0000000..15e56f1
--- /dev/null
@@ -0,0 +1 @@
+<div ng-include="'~/afGuiEditor/entityConfig/Generic.html'"></div>
diff --git a/ext/afform/gui/ang/afGuiEditor/entityConfig/Contact.html b/ext/afform/gui/ang/afGuiEditor/entityConfig/Contact.html
new file mode 100644 (file)
index 0000000..252b9c3
--- /dev/null
@@ -0,0 +1,10 @@
+<div ng-include="'~/afGuiEditor/entityConfig/Generic.html'"></div>
+<div class="form-inline">
+  <label>
+    {{ ts('Autofill as:') }}
+  </label>
+  <select ng-model="entity.autofill" class="form-control">
+    <option value="">{{ ts('None') }}</option>
+    <option value="user">{{ ts('Current User') }}</option>
+  </select>
+</div>
diff --git a/ext/afform/gui/ang/afGuiEditor/entityConfig/Generic.html b/ext/afform/gui/ang/afGuiEditor/entityConfig/Generic.html
new file mode 100644 (file)
index 0000000..88db90c
--- /dev/null
@@ -0,0 +1,6 @@
+<div class="checkbox">
+  <label>
+    <input type="checkbox" ng-model="entity['url-autofill']" ng-true-value="'1'" ng-false-value="'0'" />
+    {{ ts('Allow url autofill') }}
+  </label>
+</div>
diff --git a/ext/afform/gui/ang/afGuiEditor/entityDefaults/Activity.json b/ext/afform/gui/ang/afGuiEditor/entityDefaults/Activity.json
new file mode 100644 (file)
index 0000000..41288d8
--- /dev/null
@@ -0,0 +1,5 @@
+// Default values for creating a new entity.
+// Note this is not strict JSON - it passes through angular.$parse - $scope variables are available.
+{
+  'url-autofill': '1'
+}
diff --git a/ext/afform/gui/ang/afGuiEditor/entityDefaults/Contact.json b/ext/afform/gui/ang/afGuiEditor/entityDefaults/Contact.json
new file mode 100644 (file)
index 0000000..2ffa077
--- /dev/null
@@ -0,0 +1,9 @@
+// Default values for creating a new entity.
+// Note this is not strict JSON - it passes through angular.$parse - $scope variables are available.
+{
+  data: {
+    contact_type: 'Individual',
+    source: afform.title
+  },
+  'url-autofill': '1'
+}