Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Xiaohua Guan created an issue. See original summary.

yas’s picture

Status: Active » Needs work

@xiahua-guan,

If possible, could you please setup fieldsets as follows?

Instance
- Instance ID
- Instance State
- Instance Type
- AMI ID
- Virtualization
- Reservation
- Owner
- Launch Time

Network
- Public IP
- Private IPs
- Public DNS
- Private DNS
- Security Groups
- Key Pair Name
- VPC ID
- Subnet ID
- Availability Zone

Storage
- Root Device Type
- Root Device
- EBS Optimized

Options
- Monitoring
- AMI Launch Index
- Tenancy

Others (fieldsets closed)
- Authored by

Xiaohua Guan’s picture

Xiaohua Guan’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 3: 3022814-3.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Xiaohua Guan’s picture

FileSize
16.26 KB
Xiaohua Guan’s picture

Status: Needs work » Needs review
Xiaohua Guan’s picture

@yas

I change the following fields to link.

In detail page

  • Key Pair Name
  • Security group
  • Public IP

In edit form page

  • Key Pair Name

Because security group field is editable in edit form page, I leave the field unchanged.

Xiaohua Guan’s picture

@yas

> If possible, could you please setup fieldsets as follows?

It is difficult to setup fieldsets for the detail page. Is it ok to setup for edit form page only?

yas’s picture

Status: Needs review » Needs work

@xiaohua-guan,

Yes, that's fine to setup for edit form page.

Xiaohua Guan’s picture

FileSize
19.36 KB
Xiaohua Guan’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 11: 3022814-11.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Xiaohua Guan’s picture

FileSize
30.88 KB
Xiaohua Guan’s picture

Status: Needs work » Needs review
Xiaohua Guan’s picture

@yas

> Yes, that's fine to setup for edit form page.

I setup fieldsets for edit form. But because some fields(such as Reservation) don't exist, I arrange the fields by my judgement.

Please confirm them. Thanks.

Status: Needs review » Needs work

The last submitted patch, 14: 3022814-14.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Xiaohua Guan’s picture

Status: Needs work » Needs review
yas’s picture

@xiaohua-guan,

Thank you for the patch!

In the detail page:

  1. Could you please re-order each items like my comment #2 ?

In the edit form:

  1. Also, could you follow the order of my comment #2 ?
  2. Can you switch Network and Options?
  3. Key Pair Name: [Key Pair Name] <= Put a colon and a while space in between the label and the link
  4. And extra, can you add Instance ID above Name in Instance fieldset? (maybe we should put this as another issue)
Xiaohua Guan’s picture

FileSize
43.62 KB
Xiaohua Guan’s picture

@yas

Thanks for your comment.

My reply is below.

> In the detail page:
> Could you please re-order each items like my comment #2 ?

Yes, I reordered.

> In the edit form:
> Also, could you follow the order of my comment #2 ?

Yes, I changed the order.

> Can you switch Network and Options?

Yes, I switched them.

> Key Pair Name: [Key Pair Name] <= Put a colon and a while space in
> between the label and the link

Due to using label element which is the same with the other fields, it would be better separate label and link in different lines.

> And extra, can you add Instance ID above Name in Instance fieldset?
> (maybe we should put this as another issue)

Yes, I added instance id.

yas’s picture

@xiaohua-guan,

Thank you for the updated patch. I tried and tested it; it looks pretty good. One thing that I noticed is that as for entity_link_renderer, it looks quite generic service, therefore I assume that the namespace Drupal\cloud is the better place?

@baldwinlouie

How do you think about this patch other than my comment above?

baldwinlouie’s picture

@xiaohua-guan, @yas, Looks like a good patch! Below are my comments.

  1. +++ b/modules/cloud_service_providers/aws_cloud/src/Form/Ec2/AwsCloudContentForm.php
    @@ -40,7 +50,8 @@ class AwsCloudContentForm extends CloudContentForm {
    +      $container->get('entity.repository'),
    +      $container->get('entity_link_renderer')
    

    Can "entity_link_renderer" follow the other services and look something like "entity.link_renderer"

  2. +++ b/modules/cloud_service_providers/aws_cloud/src/Plugin/Field/FieldFormatter/EntityLinkFormatter.php
    @@ -0,0 +1,96 @@
    +      $element[$delta] = \Drupal::service('entity_link_renderer')
    +        ->renderViewElement($value, $target_type, $field_name);
    

    Can the "entity_link_renderer" be injected into the class using dependency injection?

  3. +++ b/modules/cloud_service_providers/aws_cloud/src/Service/EntityLinkRenderer.php
    @@ -0,0 +1,106 @@
    +        $htmls[] = $this->linkGenerator->generate(
    +          $value,
    +          Url::fromRoute(
    +            "entity.$target_type.canonical",
    +            [
    +              'cloud_context' => $cloud_context,
    +              $target_type => array_values($entity_ids)[0],
    +            ]
    +          )
    +        );
    

    Since this is a fairly generic service, can we pass query parameters into the renderViewElement method and have them render with the Url?

    We might not need this at the moment, but if someone wants to use the service, it should be able to handle query parameters.

yas’s picture

@xiaohua-guan,

Could you please refer to the following code for my comment for request #2 ?

The code can show fieldsets. Furthermore, I think you can find a way to generalize the class or its logic. Also, I'm afraid that it cannot show the multiple value such as Security Groups? (Maybe still needs to be improved -- by creating Ec2BaseViewBuilder as the parent class of InstanceViewBuilder)

cloud/modules/cloud_service_providers/aws_cloud/src/Entity/Ec2/Instance.php

/**
 * Defines the Instance entity.
 *
 * @ingroup aws_cloud
 *
 * @ContentEntityType(
 *   id = "aws_cloud_instance",
 *   label = @Translation("AWS Cloud Instance"),
 *   handlers = {
 *     "view_builder" = "Drupal\aws_cloud\Entity\Ec2\InstanceViewBuilder"    ,
 *     "list_builder" = "Drupal\aws_cloud\Controller\Ec2\InstanceListBuilder",
 *     "views_data"   = "Drupal\aws_cloud\Entity\Ec2\InstanceViewsData"      ,
 *
...

cloud/modules/cloud_service_providers/aws_cloud/src/Entity/Ec2/InstanceViewBuilder.php

// Created by yas 2019/01/07.
namespace Drupal\aws_cloud\Entity\Ec2;

use Drupal\Core\Entity\EntityViewBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\Element;

/**
 * Provides the views data for the CloudScripting entity type.
 */
class InstanceViewBuilder extends EntityViewBuilder {

  /**
   * {@inheritdoc}
   */
  public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {

    $fieldset_defs = [
      [
        'name' => 'instance', 'title' => t('Instance'), 'open' => TRUE,
        'fields' => [
          'instance_id',
          'name',
          'instance_type',
          'instance_state',
          'image_id',
          'virtualization',
          'reservation',
          'owner',
          'launch_time',
        ],
      ],
      [
        'name' => 'network', 'title' => t('Network'), 'open' => TRUE,
        'fields' => [
          'public_ip',
          'private_ips',
          'public_dns',
          'security_groups',
          'key_pair_name',
          'vpc_id',
          'subnet_id',
          'availability_zone',
        ],
      ],
      [
        'name' => 'storage', 'title' => t('Storage'), 'open' => TRUE,
        'fields' => [
          'root_device_type',
          'root_device',
          'ebs_optimized',
        ],
      ],
      [
        'name' => 'options', 'title' => t('Options'), 'open' => TRUE,
        'fields' => [
          'is_monitoring',
          'ami_launch_index',
          'tenancy',
        ],
      ],
    ];
  
    $weight = -50;
    foreach ($fieldset_defs as $fieldset_def) {
      $fieldset_name = $fieldset_def['name'];
      $build[$fieldset_name] = [
        '#type' => 'details',
        '#title' => $fieldset_def['title'],
        '#weight' => $weight++,
        '#tree' => TRUE,
        '#open' => $fieldset_def['open'],
      ];
  
      $params = [];
      foreach ($fieldset_def['fields'] as $field_name) {
        $params[$field_name] = $entity->get($field_name);
      }
  
      $params['user_id'] = NULL;
      $instance = Instance::create($params);
      $build[$fieldset_name][] = parent::view($instance, $view_mode, $langcode);
    }
  
    $build['others'] = [
      '#type' => 'details',
      '#title' => 'Others',
      '#tree' => TRUE,
      '#open' => FALSE,
      '#weight' => $weight++,
    ];

    $instance = Instance::create([]);
    $build['others'][] = parent::view($instance, $view_mode, $langcode);
  
    return $build;
  }

}
yas’s picture

Status: Needs review » Needs work
Xiaohua Guan’s picture

FileSize
50.4 KB
Xiaohua Guan’s picture

@yas @baldwinlouie

Thanks for your advices and code.

> 1. Can "entity_link_renderer" follow the other services and look something like "entity.link_renderer"
Yes, I changed it.

> 2. Can the "entity_link_renderer" be injected into the class using dependency injection?
Yes, I implemented using dependency injection.

> 3. Since this is a fairly generic service, can we pass query parameters into the renderViewElement method and have them render with the Url?
Yes, I added a new parameter the method.

> Could you please refer to the following code for my comment for request #2 ?
Thanks for your code. I implemented just like your sample code. Furthermore, I created a base class to include the base logic.

Please review the patch file 3022814-26.patch. Thanks.

Xiaohua Guan’s picture

FileSize
50.42 KB
Xiaohua Guan’s picture

Status: Needs work » Needs review
Xiaohua Guan’s picture

Status: Needs review » Needs work
Xiaohua Guan’s picture

FileSize
51.67 KB
Xiaohua Guan’s picture

Status: Needs work » Needs review
Xiaohua Guan’s picture

@yas @baldwinlouie

Please review the patch file 3022814-31.patch. Thanks.

yas’s picture

FileSize
44.29 KB

@xiaohua-guan,

1. In InstanceEditForm , I suggest the following:

  public function buildForm(array $form, FormStateInterface $form_state, $cloud_context = '') {
    /* @var $entity \Drupal\aws_cloud\Entity\Ec2\Instance */
    $form = parent::buildForm($form, $form_state);

    $entity = $this->entity;

    $weight = -50;

    $form['instance'] = [
      '#type' => 'details',
      '#title' => $this->t('Instance'),
      '#open' => TRUE,
      '#weight' => $weight++,
    ];

    $form['instance']['name'] = [
      '#type'          => 'textfield',
      '#title'         => $this->t('Name'),
      '#maxlength'     => 255,
      '#size'          => 60,
      '#default_value' => $entity->label(),
      '#required'      => FALSE,
    ];

    $form['instance']['instance_id'] = [
      '#type'          => 'item',
      '#title'         => $this->t('Instance ID: '),
      '#maxlength'     => 255,
      '#size'          => 60,
      '#markup'        => $entity->getInstanceId(),
      '#required'      => FALSE,
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => TRUE,
    ];

    $form['instance']['instance_type'] = [
      '#type'          => 'select',
      '#title'         => $this->t('Instance Type'),
      '#wrapped_label' => TRUE,
      '#default_value' => $entity->getInstanceType(),
      '#required'      => FALSE,
      '#options'       => $this->getInstanceTypeOptions(),
    ];

    if ($entity->getInstanceState() !== 'stopped') {
      $form['instance']['instance_type'] += [
        '#attributes'  => ['readonly' => 'readonly'],
        '#disabled'    => TRUE,
      ];
    }

    $form['instance']['image_id'] = [
      '#type'          => 'item',
      '#title'         => $this->t('AMI Image: '),
      '#markup'        => $entity->getImageId(),
      '#required'      => FALSE,
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => TRUE,
    ];

    $form['instance']['kernel_id'] = [
      '#type'          => 'item',
      '#title'         => $this->t('Kernel Image: '),
      '#markup'        => $entity->getKernelId(),
      '#required'      => FALSE,
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => TRUE,
    ];

    $form['instance']['ramdisk_id'] = [
      '#type'          => 'item',
      '#title'         => $this->t('Ramdisk Image: '),
      '#markup'        => $entity->getRamdiskId(),
      '#required'      => FALSE,
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => TRUE,
    ];

    $form['network'] = [
      '#type' => 'details',
      '#title' => $this->t('Network'),
      '#open' => TRUE,
      '#weight' => $weight++,
    ];

    $form['network']['security_groups'] = [
      '#type'          => 'select',
      '#title'         => $this->t('Security Groups'),
      '#default_value' => explode(self::SECURITY_GROUP_DELIMITER,
                                  $entity->getSecurityGroups()),
      '#required'      => TRUE,
      '#multiple'      => TRUE,
      '#options'       => $this->getSecurityGroupsOptions(),
    ];
    $this->entityLinkRenderer->renderFormElements(
      $entity->getKeyPairName(),
      'aws_cloud_key_pair',
      'key_pair_name',
      $form['network'],
      ['#title' => $this->t('Key Pair Name: ')],
      'key_pair_name'
    );

    $form['network']['availability_zone'] = [
      '#type'          => 'item',
      '#title'         => $this->t('Availability Zone: '),
      '#markup'        => $entity->getAvailabilityZone(),
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => TRUE,
    ];

    $form['options'] = [
      '#type'          => 'details',
      '#title'         => $this->t('Options'),
      '#open'          => TRUE,
      '#weight'        => $weight++,
    ];

    $form['options']['user_data'] = [
      '#type'          => 'textarea',
      '#title'         => $this->t('User Data'),
      '#maxlength'     => 4096,
      '#cols'          => 60,
      '#rows'          => 3,
      '#default_value' => $entity->getUserData(),
      '#required'      => FALSE,
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => TRUE,
      '#weight'        => $weight++,
    ];

    $form['options']['is_monitoring'] = [
      '#type'          => 'item',
      '#title'         => $this->t('Monitoring Enabled: '),
      '#markup'        => $entity->isMonitoring()
                        ? $this->t('Enabled') : $this->t('Disabled'),
      '#weight'        => $weight++,
    ];

    $form['options']['login_username'] = [
      '#type'          => 'textfield',
      '#title'         => $this->t('Login Username'),
      '#size'          => 60,
      '#default_value' => $entity->getLoginUsername() ?: 'ec2-user',
      '#weight'        => $weight++,
      '#required'      => FALSE,
    ];

    // Set a message for termination timestamp.
    $date_format = DateFormat::load('html_date')->getPattern();
    $time_format = DateFormat::load('html_time')->getPattern();

    $form['termination_timestamp']['widget'][0]['value']['#description']
      = $this->t('Format: %format. Leave blank for no automatic termination.',
                        ['%format' =>
                          Datetime::formatExample($date_format . ' ' . $time_format)
                        ]
      );
    $form['termination_timestamp']['#weight'] = $weight++;
    $form['options']['termination_timestamp'] = $form['termination_timestamp'];
    unset($form['termination_timestamp']);

    $schedule = $entity->getSchedule();
    $form['options']['schedule'] = [
      '#title' => t('Schedule'),
      '#type' => 'select',
      '#default_value' => isset($schedule) ? $entity->getSchedule() : '',
      '#options'       => aws_cloud_get_schedule(),
      '#description'   => t('Specify a start/stop schedule. This helps reduce server hosting costs.'),
      '#weight'        => $weight++,
    ];

    $form['others'] = [
      '#type'          => 'details',
      '#title'         => $this->t('Others'),
      '#open'          => FALSE,
      '#weight'        => $weight++,
    ];

    $form['others']['cloud_context'] = [
      '#type'          => 'item',
      '#title'         => $this->t('Cloud ID: '),
      '#markup'        => !$entity->isNew()
        ? $entity->getCloudContext()
        : $cloud_context,
    ];

    $form['others']['langcode'] = [
      '#title'         => t('Language'),
      '#type'          => 'language_select',
      '#default_value' => $entity->getUntranslated()->language()->getId(),
      '#languages'     => Language::STATE_ALL,
      '#attributes'    => ['readonly' => 'readonly'],
      '#disabled'      => FALSE,
    ];

    $form['others']['user_id'] = $form['user_id'];
    unset($form['user_id']);

    $form['actions'] = $this->actions($form, $form_state, $cloud_context);
    $form['actions']['#weight'] = $weight++;

    return $form;
  }

2. In my comment #19 No.3, In the edit form,

3. Key Pair Name: [Key Pair Name] <= Put a colon and a while space in between the label and the link

Please find the attached screen shot. I searched Google a lot but I couldn't find the solution, though.

3. In EntityLinkRenderer , let's align with renderFormElements

  public function renderViewElement(
    $value,
    $target_type,
    $field_name) {

4. In my comment #22,

One thing that I noticed is that as for entity_link_renderer , it looks quite generic service, therefore I assume that the namespace Drupal\cloud is the better place?

5. In EntityLinkFormatter ,

FROM:

* Constructs a EntityLinkFormatter instance.

TO:

* Constructs an EntityLinkFormatter instance.
yas’s picture

Status: Needs review » Needs work
Xiaohua Guan’s picture

FileSize
55.92 KB
Xiaohua Guan’s picture

Xiaohua Guan’s picture

@yas

Thanks for your detailed comments.

1. In InstanceEditForm , I suggest the following:

I used the code above. Furthermore, because the form element login_username is readonly, I changed the type of the form element to "item".

2. In my comment #19 No.3, In the edit form,

I modified the code of EntityLinkRenderer. Please see the screenshot.

3. In EntityLinkRenderer , let's align with renderFormElements

I fixed it.

4. In my comment #22,
One thing that I noticed is that as for entity_link_renderer , it looks quite generic service, therefore I assume that the namespace Drupal\cloud is the better place?

I moved entity_link_renderer to the module cloud, and because the field formatter entity_link is also generic one, I moved it to the module cloud too.

5. In EntityLinkFormatter ,

I fixed it as you said.

Please review the new patch again. Thanks.

yas’s picture

@xiaohua-guan,

Thank you for the updated patch, it looks fairly good!

  1. Correct me if I'm wrong, did you also move EntityLinkRenderer into cloud module?
  2. Please put a colon (:) at Login Username in the form.
Xiaohua Guan’s picture

FileSize
56.1 KB
Xiaohua Guan’s picture

@yas

1. Correct me if I'm wrong, did you also move EntityLinkRenderer into cloud module?

Yes. I moved EntityLinkRenderer to cloud module.

2. Please put a colon (:) at Login Username in the form.

OK, I modified as you said.

Please review the new patch again. Thanks.

Xiaohua Guan’s picture

FileSize
57.19 KB
Xiaohua Guan’s picture

Status: Needs work » Needs review
Xiaohua Guan’s picture

Fix some coding standard messages in #42.

Xiaohua Guan’s picture

FileSize
61.51 KB
Xiaohua Guan’s picture

FileSize
57.19 KB
Xiaohua Guan’s picture

Did some modifications for class Ec2BaseViewBuilder in 3022814-46.patch to adapt to other entity type.

Xiaohua Guan’s picture

@yas

Please review the patch file 3022814-46.patch.

yas’s picture

Status: Needs review » Reviewed & tested by the community

@xiaohua-guan,

One thing that I noticed is that it shows Monitoring: Off in the Instance detail view page, which is expected Monitoring: Disabled like in Instance Edit Page, that includes explicitly implemented, however it can be refactored later.

I'll merge the updated patch. Thank you for your hard work!

  • yas committed 0fd5563 on 8.x-1.x authored by Xiaohua Guan
    Issue #3022814 by Xiaohua Guan, yas, baldwinlouie: Use a link to a...
yas’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.