Jake Vanderwerf
2026-09-18 a6413da67a4579866f0fd0323ddb23a7b6b9654a
inc/integrations/Admin.php
@@ -9,6 +9,7 @@
trait Admin {
   use _Base;
   protected bool $canTest = false;
   //An array of AdminAction objects
   protected array $actions = [];
   protected array $instructions = [];
@@ -22,18 +23,33 @@
            'label'     => 'Save Changes',
            'icon'      => 'floppy-disk',
            'action' => [$this, 'saveCredentials']
         ],
         [
            'name'      => 'Clear Credentials',
            'icon'      => 'broom',
            'action' => [$this, 'clearCredentials']
         ],
         ]
      ];
      if ($this->isSetUp()) {
         $actions[] = [
            'name'      => 'Clear Credentials',
            'label'     => 'Clear Credentials',
            'icon'      => 'broom',
            'action' => [$this, 'deleteCredentials']
         ];
      }
      if ($this->canTest) {
         $actions[] = [
            'name'   => 'Test Connection',
            'label'  => 'Test Connection',
            'icon'   => 'plugs-connected',
            'action' => [$this, 'testConnectionAction']
         ];
      }
      foreach ($actions as $a) {
         $this->addAction($a['name'], $a['action'], $a['slug']??null, $a['icon']??null, $a['label']??null);
      }
      $this->defineActions();
   }
   abstract protected function defineActions():void;
   public function addAction(string $name, callable $callback, ?string $slug = null, ?string $icon = null, ?string $label = null):void
   {
      $action = new AdminActions($name, $callback);
@@ -78,17 +94,10 @@
      return $result;
   }
   public function response(bool $success, string $message):array
   {
      return [
         'success'   => $success,
         'message'   => $message
      ];
   }
   public function renderConnection():string
   public function renderConnection(bool $return = false):string
   {
      if ($this->userID && !JVB()->userCanConnect($this->service_name, $this->userID)) {
      if ($this->userID && !$this->userCanConnect($this->userID)) {
         return '';
      }
@@ -96,13 +105,28 @@
      $isConnected = !empty($credentials);
      $meta = '';
      if ($isConnected && array_key_exists('updated_at', $credentials) && $credentials['updated_at'] > 0) {
         $meta = sprintf(
         '<div class="meta">
               <small>Last updated: %s ago</small>
            </div>',
            human_time_diff($credentials['updated_at'])
         );
      if ($isConnected) {
         $updated = Auth::getInstance()->getLastUpdated($this->service_name, $this->userID);
         $meta = [];
         if ($updated) {
            $meta[] = sprintf(
            '<small>Last updated: %s ago</small>',
               human_time_diff(strtotime($updated))
            );
         }
         $tested = Auth::getInstance()->getLastTested($this->service_name, $this->userID);
         if ($tested && $tested !== '0000-00-00 00:00:00') {
            $meta[] = sprintf(
               '<small>Last tested: %s ago</small>',
               human_time_diff(strtotime($tested))
            );
         }
         if (!empty($meta)) {
            $meta = sprintf(
               '<div class="meta">%s</div>',
               implode('<br>', $meta)
            );
         }
      }
      $form = sprintf(
@@ -124,7 +148,7 @@
         $meta,
      );
      if (!empty($this->instructions)) {
      if (!$this->isSetUp() && !empty($this->instructions)) {
         $form .= sprintf(
            '<details%s>
               <summary>Instructions</summary>
@@ -132,13 +156,22 @@
            </details>',
            $isConnected ? '' : ' open',
            implode('',array_map(function($el) {
               if (is_array($el)) {
                  $bits = implode('', array_map(function ($b) {
                     return sprintf('<li>%s</li>', $b);
                  }, $el));
                  return sprintf('<ol>%s</ol>', $bits);
               }
               return sprintf('<li>%s</li>', $el);
            }, $this->instructions))
         );
      }
      $setupFields = array_filter($this->fields, function($field) {
         return $field->isSetupField();
      });
      if (current_user_can('manage_options')) {
      if ((method_exists($this, 'userCanConnect') && $this->userCanConnect(get_current_user_id())) || current_user_can('manage_options')) {
         $form .= sprintf(
            '<details class="initial-setup"%s>
            <summary>Setup</summary>
@@ -146,7 +179,7 @@
            %s
         </details>',
            $isConnected ? '' : ' open',
            $this->outputFields($this->credentialFields),
            $this->outputFields($setupFields),
            method_exists($this, 'renderWebhookUrl') ? $this->renderWebhookUrl() : ''
         );
      }
@@ -155,16 +188,35 @@
         $form .= $this->renderOAuthConnectionForm();
      }
      if (!empty($this->optionalFields) || $this->hasExtraOptions) {
         $form .= '<div class="integration-content">';
         if (!empty($this->optionalFields)) {
            $form .= sprintf(
      $advancedFields = array_filter($this->fields, function($field) {
         return $field->isAdvancedField();
      });
      if (!empty($advancedFields) && $this->isSetUp()) {
         $form .= sprintf(
            '<details class="advanced">
                  <summary>Advanced Settings</summary>%s</details>',
               $this->outputFields($this->optionalFields)
            <summary>Advanced Options</summary>
            %s
         </details>',
            $this->outputFields($advancedFields),
         );
      }
      $optionalFields = array_filter($this->fields, function($field) {
         return $field->isAdditionalField();
      });
      if ($this->isSetUp() && (!empty($optionalFields) || $this->hasExtraOptions())) {
         $form .= '<div class="integration-content">';
         if (!empty($optionalFields)) {
            $form .= sprintf(
            '<details class="advanced"%s>
                  <summary>Optional Settings</summary>%s</details>',
               $this->isSetUp() ? ' open' : '',
               $this->outputFields($optionalFields)
            );
         }
         if ($this->hasExtraOptions) {
         if ($this->hasExtraOptions()) {
            $form .= sprintf(
               '<a href="%s" class="btn">More Settings</a>',
               $this->determineOptionPage()
@@ -176,6 +228,10 @@
      $form .= $this->outputActionButtons();
      $form .= '</form>';
      if (!$return) {
         echo $form;
      }
      return $form;
   }
      protected function outputActionButtons():string
@@ -188,7 +244,7 @@
            $label .= $action->getLabel();
            return sprintf(
               '<button type="button" data-action="%s"%s%s>%s</button>',
               $action->getSlug,
               $action->getSlug(),
               $action->getName(),
               empty($action->getConfirm()) ? '' : ' data-confirm="'.$action->getConfirm().'"',
               $label
@@ -210,6 +266,13 @@
         if (!empty($value)) {
            $config['readonly'] = true;
         }
         if (!empty($value) && $f->isHideStored()) {
            return sprintf(
               '<span class="label">%s</span><code>%s</code>',
               $config['label'],
               preg_replace('/.(?=.{4})/', '*', $value)
            );
         }
         $config['base'] = $this->service_name.'_';
         return Form::render($f->name, $value, $f->getConfig());
      }, $fields));
@@ -229,5 +292,16 @@
         $this->fields[$name]->setRequired();
         return true;
      }
      public function updateField(string $name, Field $field):void
      {
         $this->fields[$name] = $field;
      }
   public function testConnectionAction(?array $data = null):array
   {
      $success = $this->testConnection();
      $message = $success ? 'Successfully tested connection' : 'Could not test connection';
      return $this->response($success, $message);
   }
}