Index: src/Plugin/views/field/EntityFormField.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/Plugin/views/field/EntityFormField.php b/src/Plugin/views/field/EntityFormField.php
--- a/src/Plugin/views/field/EntityFormField.php	
+++ b/src/Plugin/views/field/EntityFormField.php	(date 1724408884789)
@@ -8,6 +8,7 @@
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\WidgetPluginManager;
@@ -279,6 +280,9 @@
    * {@inheritdoc}
    */
   public function getCacheTags() {
+    if ($this->field === 'form_field_submit_row') {
+      return [];
+    }
     $field_definition = $this->getBundleFieldDefinition();
     $field_storage_definition = $field_definition->getFieldStorageDefinition();
 
@@ -354,6 +358,7 @@
     $options['plugin']['contains']['type']['default'] = [];
     $options['plugin']['contains']['settings']['default'] = [];
     $options['plugin']['contains']['third_party_settings']['default'] = [];
+    $options['plugin']['contains']['submit_row_text']['default'] = $this->t('Save');
 
     return $options;
   }
@@ -364,61 +369,72 @@
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
-    $field_definition = $this->getBundleFieldDefinition();
+    if ($this->field === 'form_field_submit_row') {
+      $form['plugin'] = [
+        'submit_row_text' => [
+          '#type' => 'textfield',
+          '#title' => $this->t('Submit button text'),
+          '#default_value' => $this->options['plugin']['submit_row_text'],
+        ],
+      ];
+    }
+    else {
+      $field_definition = $this->getBundleFieldDefinition();
 
-    $form['plugin'] = [
-      'type' => [
-        '#type' => 'select',
-        '#title' => $this->t('Widget type'),
-        '#options' => $this->getPluginApplicableOptions($field_definition),
-        '#default_value' => $this->options['plugin']['type'],
-        '#attributes' => ['class' => ['field-plugin-type']],
-        '#ajax' => [
-          'url' => views_ui_build_form_url($form_state),
-        ],
-        '#submit' => [[$this, 'submitTemporaryForm']],
-        '#executes_submit_callback' => TRUE,
-      ],
-      'hide_title' => [
-        '#type' => 'checkbox',
-        '#title' => $this->t('Hide widget title'),
-        '#default_value' => $this->options['plugin']['hide_title'],
-      ],
-      'hide_description' => [
-        '#type' => 'checkbox',
-        '#title' => $this->t('Hide widget description'),
-        '#default_value' => $this->options['plugin']['hide_description'],
-      ],
-      'settings_edit_form' => [],
-    ];
+      $form['plugin'] = [
+        'type' => [
+          '#type' => 'select',
+          '#title' => $this->t('Widget type'),
+          '#options' => $this->getPluginApplicableOptions($field_definition),
+          '#default_value' => $this->options['plugin']['type'],
+          '#attributes' => ['class' => ['field-plugin-type']],
+          '#ajax' => [
+            'url' => views_ui_build_form_url($form_state),
+          ],
+          '#submit' => [[$this, 'submitTemporaryForm']],
+          '#executes_submit_callback' => TRUE,
+        ],
+        'hide_title' => [
+          '#type' => 'checkbox',
+          '#title' => $this->t('Hide widget title'),
+          '#default_value' => $this->options['plugin']['hide_title'],
+        ],
+        'hide_description' => [
+          '#type' => 'checkbox',
+          '#title' => $this->t('Hide widget description'),
+          '#default_value' => $this->options['plugin']['hide_description'],
+        ],
+        'settings_edit_form' => [],
+      ];
 
-    // Generate the settings form and allow other modules to alter it.
-    if ($plugin = $this->getPluginInstance()) {
-      $settings_form = $plugin->settingsForm($form, $form_state);
+      // Generate the settings form and allow other modules to alter it.
+      if ($plugin = $this->getPluginInstance()) {
+        $settings_form = $plugin->settingsForm($form, $form_state);
 
-      // Adds the widget third party settings forms.
-      //https://www.drupal.org/node/3000490
-      $third_party_settings_form = [];
-      $this->moduleHandler->invokeAllWith('field_widget_third_party_settings_form', function (callable $hook, string $module) use ($form_state, $form, $field_definition, $plugin, &$third_party_settings_form) {
-        $third_party_settings_form[$module] = $this->moduleHandler->invoke($module, 'field_widget_third_party_settings_form', [
-          $plugin,
-          $field_definition,
-          'views_view',
-          $form,
-          $form_state,
-        ]);
-      });
+        // Adds the widget third party settings forms.
+        // https://www.drupal.org/node/3000490
+        $third_party_settings_form = [];
+        $this->moduleHandler->invokeAllWith('field_widget_third_party_settings_form', function (callable $hook, string $module) use ($form_state, $form, $field_definition, $plugin, &$third_party_settings_form) {
+          $third_party_settings_form[$module] = $this->moduleHandler->invoke($module, 'field_widget_third_party_settings_form', [
+            $plugin,
+            $field_definition,
+            'views_view',
+            $form,
+            $form_state,
+          ]);
+        });
 
-      if ($settings_form || $third_party_settings_form) {
-        $form['plugin']['#cell_attributes'] = ['colspan' => 3];
-        $form['plugin']['settings_edit_form'] = [
-          '#type' => 'fieldset',
-          '#title' => $this->t('Widget settings'),
-          '#attributes' => ['class' => ['field-plugin-settings-edit-form']],
-          'settings' => $settings_form,
-          'third_party_settings' => $third_party_settings_form,
-        ];
-        $form['#attributes']['class'][] = 'field-plugin-settings-editing';
+        if ($settings_form || $third_party_settings_form) {
+          $form['plugin']['#cell_attributes'] = ['colspan' => 3];
+          $form['plugin']['settings_edit_form'] = [
+            '#type' => 'fieldset',
+            '#title' => $this->t('Widget settings'),
+            '#attributes' => ['class' => ['field-plugin-settings-edit-form']],
+            'settings' => $settings_form,
+            'third_party_settings' => $third_party_settings_form,
+          ];
+          $form['#attributes']['class'][] = 'field-plugin-settings-editing';
+        }
       }
     }
   }
@@ -443,11 +459,14 @@
    */
   public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
-
-    $options = &$form_state->getValue('options');
-    $options['plugin']['settings'] = isset($options['plugin']['settings_edit_form']['settings']) ? array_intersect_key($options['plugin']['settings_edit_form']['settings'], $this->fieldWidgetManager->getDefaultSettings($options['plugin']['type'])) : [];
-    $options['plugin']['third_party_settings'] = isset($options['plugin']['settings_edit_form']['third_party_settings']) ? $options['plugin']['settings_edit_form']['third_party_settings'] : [];
-    unset($options['plugin']['settings_edit_form']);
+    if ($this->field !== 'form_field_submit_row') {
+      $options = &$form_state->getValue('options');
+      $options['plugin']['settings'] = isset($options['plugin']['settings_edit_form']['settings']) ? array_intersect_key($options['plugin']['settings_edit_form']['settings'], $this->fieldWidgetManager->getDefaultSettings($options['plugin']['type'])) : [];
+      $options['plugin']['third_party_settings'] = $options['plugin']['settings_edit_form']['third_party_settings'] ?? [];
+    }
+    if (isset($options['plugin']['settings_edit_form'])) {
+      unset($options['plugin']['settings_edit_form']);
+    }
   }
 
   /**
@@ -484,9 +503,21 @@
         // Initialize this row and column.
         $form[$this->options['id']][$row_index]['#parents'] = [$this->options['id'], $row_index];
         $form[$this->options['id']][$row_index]['#tree'] = TRUE;
+        if ($this->field === 'form_field_submit_row') {
+          $form[$this->options['id']][$row_index]['submit'] = [
+            '#type' => 'submit',
+            '#value' => $this->options['plugin']['submit_row_text'],
+            '#name' => 'submit-' . $this->options['id'] . '-' . $row_index,
+            '#submit' => [[$this, 'saveEntities']],
+            '#row_index' => $row_index,
+            '#limit_validation_errors' => [
+              [$this->options['id'], $row_index],
+            ],
+          ];
+        }
 
         // Make sure there's an entity for this row (relationships can be null).
-        if ($this->getEntity($row)) {
+        if ($this->getEntity($row) && $this->field !== 'form_field_submit_row') {
           // Load field definition based on current entity bundle.
           $entity = $this->getEntityTranslation($this->getEntity($row), $row);
           if ($entity->hasField($field_name) && $this->getBundleFieldDefinition($entity->bundle())->isDisplayConfigurable('form')) {
@@ -562,24 +593,46 @@
    */
   protected function buildEntities(array &$form, FormStateInterface $form_state, $validate = FALSE) {
     $field_name = $this->definition['field_name'];
+    $triggering_element = $form_state->getTriggeringElement();
+    if (isset($triggering_element['#row_index'])) {
+      $row_index = $triggering_element['#row_index'];
+      $this->buildEntity($form, $form_state, $this->getView()->result[$row_index], $field_name, $validate);
+      return;
+    }
 
     // Set this value back to it's relevant entity from each row.
     foreach ($this->getView()->result as $row_index => $row) {
-      // Check to make sure that this entity has a relevant field.
-      $entity = $this->getEntity($row);
-      if ($entity && $entity->hasField($field_name) && $this->getBundleFieldDefinition($entity->bundle())->isDisplayConfigurable('form')) {
-        // Get current entity field values.
-        $items = $entity->get($field_name)->filterEmptyItems();
+      $this->buildEntity($form, $form_state, $row, $field_name, $validate);
+    }
+  }
+
+  /**
+   * Update entity object based upon the submitted form values.
+   *
+   * @param array $form
+   *   A nested array form elements comprising the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param \Drupal\views\ResultRow $row
+   *   The current views row.
+   * @param bool $validate
+   *   Validate the entity after extracting form values.
+   */
+  protected function buildEntity(array &$form, FormStateInterface $form_state, ResultRow $row, string $field_name, $validate = FALSE) {
+    // Check to make sure that this entity has a relevant field.
+    $entity = $this->getEntity($row);
+    if ($entity && $entity->hasField($field_name) && $this->getBundleFieldDefinition($entity->bundle())->isDisplayConfigurable('form')) {
+      // Get current entity field values.
+      $items = $entity->get($field_name)->filterEmptyItems();
 
-        // Extract values.
-        $this->getPluginInstance($entity->bundle())->extractFormValues($items, $form[$this->options['id']][$row_index], $form_state);
+      // Extract values.
+      $this->getPluginInstance($entity->bundle())->extractFormValues($items, $form[$this->options['id']][$row->index], $form_state);
 
-        // Validate entity and add violations to field widget.
-        if ($validate) {
-          $violations = $items->validate();
-          if ($violations->count() > 0) {
-            $this->getPluginInstance($entity->bundle())->flagErrors($items, $violations, $form[$this->options['id']][$row_index], $form_state);
-          }
+      // Validate entity and add violations to field widget.
+      if ($validate) {
+        $violations = $items->validate();
+        if ($violations->count() > 0) {
+          $this->getPluginInstance($entity->bundle())->flagErrors($items, $violations, $form[$this->options['id']][$row->index], $form_state);
         }
       }
     }
@@ -600,22 +653,15 @@
 
       $rows_saved = [];
       $rows_failed = [];
-
-      foreach ($this->getView()->result as $row_index => $row) {
-        $entity = $this->getEntity($row);
-
-        if ($entity) {
-          $entity = $this->getEntityTranslation($entity, $row);
-          $original_entity = $this->getEntityTranslation($storage->loadUnchanged($entity->id()), $row);
-
-          try {
-            if ($this->entityShouldBeSaved($entity, $original_entity)) {
-              $storage->save($entity);
-              $rows_saved[$row_index] = $entity->label();
-            }
-          } catch (\Exception $exception) {
-            $rows_failed[$row_index] = $entity->label();
-          }
+      $triggering_element = $form_state->getTriggeringElement();
+      if (isset($triggering_element['#row_index'])) {
+        $row_index = $triggering_element['#row_index'];
+        $row = $this->getView()->result[$row_index];
+        $this->processEntityFromRow($row, $storage, $rows_saved, $rows_failed);
+      }
+      else {
+        foreach ($this->getView()->result as $row_index => $row) {
+          $this->processEntityFromRow($row, $storage, $rows_saved, $rows_failed);
         }
       }
 
@@ -643,12 +689,66 @@
     }
   }
 
+  /**
+   * Process an entity from a row for saving.
+   *
+   * @param \Drupal\views\ResultRow $row
+   *   The row to process.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
+   *   The entity storage.
+   * @param array $rows_saved
+   *   The rows that were saved.
+   * @param array $rows_failed
+   *   The rows that failed to save.
+   */
+  protected function processEntityFromRow(ResultRow $row, EntityStorageInterface $storage, array &$rows_saved, array &$rows_failed) {
+    $entity = $this->getEntity($row);
+
+    if ($entity) {
+      $entity = $this->getEntityTranslation($entity, $row);
+      $original_entity = $this->getEntityTranslation($storage->loadUnchanged($entity->id()), $row);
+
+      if ($this->saveEntity($entity, $original_entity, $storage)) {
+        $rows_saved[$row->index] = $entity->label();
+      }
+      else {
+        $rows_failed[$row->index] = $entity->label();
+      }
+    }
+  }
+
+  /**
+   * Save view entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to save.
+   * @param \Drupal\Core\Entity\EntityInterface $original_entity
+   *   The original entity.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
+   *   The entity storage.
+   *
+   * @return bool
+   *   TRUE if the entity was saved; FALSE otherwise.
+   */
+  protected function saveEntity(EntityInterface $entity, EntityInterface $original_entity, EntityStorageInterface $storage): bool {
+    try {
+      if ($this->entityShouldBeSaved($entity, $original_entity)) {
+        $storage->save($entity);
+        return TRUE;
+      }
+    }
+    catch (\Exception $exception) {
+      return FALSE;
+    }
+    return FALSE;
+  }
+
   /**
    * Determines if an entity should be saved.
    *
-   * @param EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The possibly modified entity in question.
-   * @param EntityInterface $original_entity
+   * @param \Drupal\Core\Entity\EntityInterface $original_entity
    *   The original unmodified entity.
    *
    * @return bool
Index: views_entity_form_field.module
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/views_entity_form_field.module b/views_entity_form_field.module
--- a/views_entity_form_field.module	
+++ b/views_entity_form_field.module	(date 1724409085968)
@@ -69,6 +69,17 @@
           'field_name' => $field_name,
         ];
       }
+      if ($bundle_info[$entity_type_id]) {
+        // Add submit button for row.
+        $data[$views_table]['form_field_submit_row']['field'] = [
+          'title' => t('Form field: Submit button'),
+          'help' => t('Add a submit button to the row.'),
+          'id' => 'entity_form_field',
+          'bundles' => array_keys($bundle_info[$entity_type_id]),
+          'entity_type' => $entity_type_id,
+          'field_name' => 'form_field_submit_row',
+        ];
+      }
     }
   }
 }
