From 0e69b25854a0f4e09ba336a28deab80551b576b6 Mon Sep 17 00:00:00 2001
From: Peter Hegman <phegman@gitlab.com>
Date: Tue, 28 Jun 2022 22:28:17 +0000
Subject: [PATCH] Refactor import group name and path field to Vue

To improve UX and remove HAML/jQuery
---
 .../_import_group_from_file_panel.html.haml   |  63 +++++-----
 .../_group_name_and_path_fields.html.haml     |   2 +-
 .../groups/import_export/import_file_spec.rb  | 112 ++++++++++++++++--
 3 files changed, 136 insertions(+), 41 deletions(-)

diff --git a/app/views/groups/_import_group_from_file_panel.html.haml b/app/views/groups/_import_group_from_file_panel.html.haml
index 04170c30a2074..2e524e6567954 100644
--- a/app/views/groups/_import_group_from_file_panel.html.haml
+++ b/app/views/groups/_import_group_from_file_panel.html.haml
@@ -2,46 +2,49 @@
 - group_path = root_url
 - group_path << parent.full_path + '/' if parent
 
-= form_with url: import_gitlab_group_path, class: 'group-form gl-show-field-errors', multipart: true do |f|
+= form_for '', url: import_gitlab_group_path, namespace: ('import_group' if Feature::enabled?(:group_name_path_vue, current_user)), class: 'group-form gl-show-field-errors', multipart: true do |f|
   .gl-border-l-solid.gl-border-r-solid.gl-border-gray-100.gl-border-1.gl-p-5
     %h4
       = _('Import group from file')
     = render Pajamas::AlertComponent.new(variant: :warning,
+      alert_options: { class: 'gl-mb-5' },
       dismissible: false) do |c|
       = c.body do
         - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md') }
         - link_end = '</a>'.html_safe
         = s_('GroupsNew|This feature is deprecated and replaced by %{docs_link_start}group migration%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: link_end }
-
-    .form-group.gl-display-flex.gl-flex-direction-column.gl-mt-5
-      = f.label :name, _('New group name'), for: 'import_group_name'
-      = f.text_field :name, placeholder: s_('GroupsNew|My Awesome Group'), class: 'js-autofill-group-name gl-form-input col-xs-12 col-sm-8',
-        required: true,
-        title: _('Please fill in a descriptive name for your group.'),
-        autofocus: true,
-        id: 'import_group_name'
-
-    .form-group.gl-display-flex.gl-flex-direction-column
-      = f.label :import_group_path, _('New group URL'), for: 'import_group_path'
-      .input-group.gl-field-error-anchor.col-xs-12.col-sm-8.gl-p-0
-        .group-root-path.input-group-prepend.has-tooltip{ title: group_path, :'data-placement' => 'bottom' }
-          .input-group-text
-            %span
-              = root_url
-            - if parent
-              %strong= parent.full_path + '/'
-        = f.hidden_field :parent_id, value: parent&.id
-        = f.text_field :path, placeholder: 'my-awesome-group', class: 'form-control js-validate-group-path js-autofill-group-path',
-          id: 'import_group_path',
+    - if Feature::enabled?(:group_name_path_vue, current_user)
+      = render 'shared/groups/group_name_and_path_fields', f: f
+    - else
+      .form-group.gl-display-flex.gl-flex-direction-column.gl-mt-5
+        = f.label :name, _('New group name'), for: 'import_group_name'
+        = f.text_field :name, placeholder: s_('GroupsNew|My Awesome Group'), class: 'js-autofill-group-name gl-form-input col-xs-12 col-sm-8',
           required: true,
-          pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
-          title: group_url_error_message,
-          maxlength: ::Namespace::URL_MAX_LENGTH,
-          "data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
-      %p.validation-error.gl-field-error.field-validation.hide
-        = _("Group path is already taken. We've suggested one that is available.")
-      %p.validation-success.gl-field-success.field-validation.hide= _('Group path is available.')
-      %p.validation-pending.gl-field-error-ignore.field-validation.hide= _('Checking group path availability...')
+          title: _('Please fill in a descriptive name for your group.'),
+          autofocus: true,
+          id: 'import_group_name'
+
+      .form-group.gl-display-flex.gl-flex-direction-column
+        = f.label :import_group_path, _('New group URL'), for: 'import_group_path'
+        .input-group.gl-field-error-anchor.col-xs-12.col-sm-8.gl-p-0
+          .group-root-path.input-group-prepend.has-tooltip{ title: group_path, :'data-placement' => 'bottom' }
+            .input-group-text
+              %span
+                = root_url
+              - if parent
+                %strong= parent.full_path + '/'
+          = f.hidden_field :parent_id, value: parent&.id
+          = f.text_field :path, placeholder: 'my-awesome-group', class: 'form-control js-validate-group-path js-autofill-group-path',
+            id: 'import_group_path',
+            required: true,
+            pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
+            title: group_url_error_message,
+            maxlength: ::Namespace::URL_MAX_LENGTH,
+            "data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
+        %p.validation-error.gl-field-error.field-validation.hide
+          = _("Group path is already taken. We've suggested one that is available.")
+        %p.validation-success.gl-field-success.field-validation.hide= _('Group path is available.')
+        %p.validation-pending.gl-field-error-ignore.field-validation.hide= _('Checking group path availability...')
     .form-group
       = f.label :file, s_('GroupsNew|Upload file')
       .gl-font-weight-normal
diff --git a/app/views/shared/groups/_group_name_and_path_fields.html.haml b/app/views/shared/groups/_group_name_and_path_fields.html.haml
index 709130a47d3b6..634b8448535d5 100644
--- a/app/views/shared/groups/_group_name_and_path_fields.html.haml
+++ b/app/views/shared/groups/_group_name_and_path_fields.html.haml
@@ -1,5 +1,5 @@
 .js-group-name-and-path{ data: group_name_and_path_app_data(@group) }
   = f.hidden_field :name, data: { js_name: 'name' }
   = f.hidden_field :path, maxlength: ::Namespace::URL_MAX_LENGTH, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, data: { js_name: 'path' }
-  = f.hidden_field :parent_id, data: { js_name: 'parentId' }
+  = f.hidden_field :parent_id, value: @group.parent&.id, data: { js_name: 'parentId' }
   = f.hidden_field :id, data: { js_name: 'groupId' }
diff --git a/spec/features/groups/import_export/import_file_spec.rb b/spec/features/groups/import_export/import_file_spec.rb
index 3d23451feef7d..4147b4982df19 100644
--- a/spec/features/groups/import_export/import_file_spec.rb
+++ b/spec/features/groups/import_export/import_file_spec.rb
@@ -20,6 +20,94 @@
     FileUtils.rm_rf(import_path, secure: true)
   end
 
+  context 'when `group_name_path_vue` feature flag is disabled' do
+    before do
+      stub_feature_flags(group_name_path_vue: false)
+    end
+
+    context 'when the user uploads a valid export file' do
+      let(:file) { File.join(Rails.root, 'spec', %w[fixtures group_export.tar.gz]) }
+
+      context 'when using the pre-filled path', :sidekiq_inline do
+        it 'successfully imports the group' do
+          group_name = 'Test Group Import'
+
+          visit new_group_path
+          click_link 'Import group'
+
+          fill_in :import_group_name, with: group_name
+
+          expect(page).to have_content 'Import group from file'
+          attach_file(file) do
+            find('.js-filepicker-button').click
+          end
+
+          expect { click_on 'Import' }.to change { Group.count }.by 1
+
+          group = Group.find_by(name: group_name)
+
+          expect(group).not_to be_nil
+          expect(group.description).to eq 'A voluptate non sequi temporibus quam at.'
+          expect(group.path).to eq 'test-group-import'
+          expect(group.import_state.status).to eq GroupImportState.state_machine.states[:finished].value
+        end
+      end
+
+      context 'when modifying the pre-filled path' do
+        it 'successfully imports the group' do
+          visit new_group_path
+          click_link 'Import group'
+
+          fill_in :import_group_name, with: 'Test Group Import'
+
+          fill_in :import_group_path, with: 'custom-path'
+          attach_file(file) do
+            find('.js-filepicker-button').click
+          end
+
+          expect { click_on 'Import' }.to change { Group.count }.by 1
+
+          group = Group.find_by(name: 'Test Group Import')
+          expect(group.path).to eq 'custom-path'
+        end
+      end
+
+      context 'when the path is already taken' do
+        before do
+          create(:group, path: 'test-group-import')
+        end
+
+        it 'suggests a unique path' do
+          visit new_group_path
+          click_link 'Import group'
+
+          fill_in :import_group_path, with: 'test-group-import'
+          expect(page).to have_content "Group path is already taken. We've suggested one that is available."
+        end
+      end
+    end
+
+    context 'when the user uploads an invalid export file' do
+      let(:file) { File.join(Rails.root, 'spec', %w[fixtures big-image.png]) }
+
+      it 'displays an error', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/343995' do
+        visit new_group_path
+        click_link 'Import group'
+
+        fill_in :import_group_name, with: 'Test Group Import'
+        attach_file(file) do
+          find('.js-filepicker-button').click
+        end
+
+        expect { click_on 'Import' }.not_to change { Group.count }
+
+        page.within('.flash-container') do
+          expect(page).to have_content('Unable to process group import file')
+        end
+      end
+    end
+  end
+
   context 'when the user uploads a valid export file' do
     let(:file) { File.join(Rails.root, 'spec', %w[fixtures group_export.tar.gz]) }
 
@@ -30,7 +118,7 @@
         visit new_group_path
         click_link 'Import group'
 
-        fill_in :import_group_name, with: group_name
+        fill_in s_('Groups|Group name'), with: group_name
 
         expect(page).to have_content 'Import group from file'
         attach_file(file) do
@@ -41,10 +129,12 @@
 
         group = Group.find_by(name: group_name)
 
-        expect(group).not_to be_nil
-        expect(group.description).to eq 'A voluptate non sequi temporibus quam at.'
-        expect(group.path).to eq 'test-group-import'
-        expect(group.import_state.status).to eq GroupImportState.state_machine.states[:finished].value
+        aggregate_failures do
+          expect(group).not_to be_nil
+          expect(group.description).to eq 'A voluptate non sequi temporibus quam at.'
+          expect(group.path).to eq 'test-group-import'
+          expect(group.import_state.status).to eq GroupImportState.state_machine.states[:finished].value
+        end
       end
     end
 
@@ -53,9 +143,9 @@
         visit new_group_path
         click_link 'Import group'
 
-        fill_in :import_group_name, with: 'Test Group Import'
+        fill_in s_('Groups|Group name'), with: 'Test Group Import'
 
-        fill_in :import_group_path, with: 'custom-path'
+        fill_in s_('Groups|Group URL'), with: 'custom-path'
         attach_file(file) do
           find('.js-filepicker-button').click
         end
@@ -76,8 +166,10 @@
         visit new_group_path
         click_link 'Import group'
 
-        fill_in :import_group_path, with: 'test-group-import'
-        expect(page).to have_content "Group path is already taken. We've suggested one that is available."
+        fill_in s_('Groups|Group URL'), with: 'test-group-import'
+        expect(page).to have_content s_(
+          'Groups|Group path is unavailable. Path has been replaced with a suggested available path.'
+        )
       end
     end
   end
@@ -89,7 +181,7 @@
       visit new_group_path
       click_link 'Import group'
 
-      fill_in :import_group_name, with: 'Test Group Import'
+      fill_in s_('Groups|Group name'), with: 'Test Group Import'
       attach_file(file) do
         find('.js-filepicker-button').click
       end
-- 
GitLab