From db3ba2aadb8c8ace65d01cde1a3cf089191f2880 Mon Sep 17 00:00:00 2001 From: Gregor Lasnibat Date: Fri, 19 Apr 2024 16:28:00 +0200 Subject: [PATCH] Create 'import mapping' step [SCI-10579] --- app/controllers/repositories_controller.rb | 17 +- .../vue/repositories/modals/import.vue | 106 +++--- .../repositories/modals/import/first_step.vue | 33 +- .../modals/import/second_step.vue | 329 ++++++++++++++++++ .../modals/import/second_step_table_row.vue | 117 +++++++ app/javascript/vue/shared/info_modal.vue | 35 +- app/javascript/vue/shared/select_dropdown.vue | 5 +- app/models/repository.rb | 4 +- app/models/repository_checklist_value.rb | 1 - app/serializers/repository_cell_serializer.rb | 15 + app/serializers/repository_row_serializer.rb | 6 +- app/serializers/repository_serializer.rb | 9 +- .../import_repository/import_records.rb | 9 +- app/services/repository_csv_export.rb | 11 +- .../repository_import_parser/importer.rb | 48 +-- config/locales/en.yml | 60 +++- 16 files changed, 683 insertions(+), 122 deletions(-) create mode 100644 app/javascript/vue/repositories/modals/import/second_step.vue create mode 100644 app/javascript/vue/repositories/modals/import/second_step_table_row.vue create mode 100644 app/serializers/repository_cell_serializer.rb diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 5b0fcacca..9fa67dde3 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -327,13 +327,14 @@ class RepositoriesController < ApplicationController .find_by_id(import_params[:id])) # Access the checkbox values from params - can_edit_existing_items = params[:edit_existing_items_checkbox] - should_overwrite_with_empty_cells = params[:overwrite_with_empty_cells] + can_edit_existing_items = params[:can_edit_existing_items] + should_overwrite_with_empty_cells = params[:should_overwrite_with_empty_cells] + preview = params[:preview] # Check if there exist mapping for repository record (it's mandatory) if import_params[:mappings].present? && import_params[:mappings].value?('-1') import_records = repostiory_import_actions - status = import_records.import!(can_edit_existing_items, should_overwrite_with_empty_cells) + status = import_records.import!(can_edit_existing_items, should_overwrite_with_empty_cells, preview) if status[:status] == :ok log_activity(:import_inventory_items, @@ -343,10 +344,12 @@ class RepositoriesController < ApplicationController number_of_rows: status[:nr_of_added], total_nr: status[:total_nr]) - log_activity(:item_added_with_import, - num_of_items: status[:nr_of_added]) + if preview + render json: status, status: :ok + else + render json: {}, status: :ok + end - render json: {}, status: :ok else flash[:alert] = t('repositories.import_records.partial_success_flash', @@ -558,7 +561,7 @@ class RepositoriesController < ApplicationController end def import_params - params.permit(:id, :file, :file_id, mappings: {}).to_h + params.permit(:id, :file, :file_id, :preview, mappings: {}).to_h end def repository_response(message) diff --git a/app/javascript/vue/repositories/modals/import.vue b/app/javascript/vue/repositories/modals/import.vue index 794e627ad..d462f292e 100644 --- a/app/javascript/vue/repositories/modals/import.vue +++ b/app/javascript/vue/repositories/modals/import.vue @@ -3,12 +3,15 @@ :startHidden="true" :infoParams="infoParams" :title="steps[activeStep].title" - :helpText="steps[activeStep].helpText"> + :subtitle="steps[activeStep].subtitle" + :helpText="steps[activeStep].helpText" + > @@ -19,86 +22,91 @@ import { shallowRef } from 'vue'; import InfoModal from '../../shared/info_modal.vue'; import FirstStep from './import/first_step.vue'; +import SecondStep from './import/second_step.vue'; export default { name: 'ImportRepositoryModal', - components: { InfoModal, FirstStep }, + components: { InfoModal, FirstStep, SecondStep }, props: { - repositoryUrl: String, required: true + repositoryUrl: String, + required: true }, data() { return { activeStep: 0, + repositoryData: null, steps: [ { - id: I18n.t('repositories.import_records.steps.step0.id'), - icon: I18n.t('repositories.import_records.steps.step0.icon'), - label: I18n.t('repositories.import_records.steps.step0.label'), - title: I18n.t('repositories.import_records.steps.step0.title'), - helpText: I18n.t('repositories.import_records.steps.step0.helpText'), - component: shallowRef(FirstStep) + id: this.i18n.t('repositories.import_records.steps.step1.id'), + icon: this.i18n.t('repositories.import_records.steps.step1.icon'), + label: this.i18n.t('repositories.import_records.steps.step1.label'), + title: this.i18n.t('repositories.import_records.steps.step1.title'), + subtitle: this.i18n.t('repositories.import_records.steps.step1.subtitle'), + helpText: this.i18n.t('repositories.import_records.steps.step1.helpText'), + component: shallowRef(FirstStep), + stepData: null + }, + { + id: this.i18n.t('repositories.import_records.steps.step2.id'), + icon: this.i18n.t('repositories.import_records.steps.step2.icon'), + label: this.i18n.t('repositories.import_records.steps.step2.label'), + title: this.i18n.t('repositories.import_records.steps.step2.title'), + subtitle: this.i18n.t('repositories.import_records.steps.step2.subtitle'), + component: shallowRef(SecondStep), + stepData: null } ], infoParams: { - title: I18n.t('repositories.import_records.info_sidebar.title'), + title: this.i18n.t('repositories.import_records.info_sidebar.title'), elements: [ { - id: I18n.t('repositories.import_records.info_sidebar.elements.element0.id'), - icon: I18n.t('repositories.import_records.info_sidebar.elements.element0.icon'), - label: I18n.t('repositories.import_records.info_sidebar.elements.element0.label'), - subtext: I18n.t('repositories.import_records.info_sidebar.elements.element0.subtext') + id: this.i18n.t('repositories.import_records.info_sidebar.elements.element0.id'), + icon: this.i18n.t('repositories.import_records.info_sidebar.elements.element0.icon'), + label: this.i18n.t('repositories.import_records.info_sidebar.elements.element0.label'), + subtext: this.i18n.t('repositories.import_records.info_sidebar.elements.element0.subtext') }, { - id: I18n.t('repositories.import_records.info_sidebar.elements.element1.id'), - icon: I18n.t('repositories.import_records.info_sidebar.elements.element1.icon'), - label: I18n.t('repositories.import_records.info_sidebar.elements.element1.label'), - subtext: I18n.t('repositories.import_records.info_sidebar.elements.element1.subtext') + id: this.i18n.t('repositories.import_records.info_sidebar.elements.element1.id'), + icon: this.i18n.t('repositories.import_records.info_sidebar.elements.element1.icon'), + label: this.i18n.t('repositories.import_records.info_sidebar.elements.element1.label'), + subtext: this.i18n.t('repositories.import_records.info_sidebar.elements.element1.subtext') }, { - id: I18n.t('repositories.import_records.info_sidebar.elements.element2.id'), - icon: I18n.t('repositories.import_records.info_sidebar.elements.element2.icon'), - label: I18n.t('repositories.import_records.info_sidebar.elements.element2.label'), - subtext: I18n.t('repositories.import_records.info_sidebar.elements.element2.subtext') + id: this.i18n.t('repositories.import_records.info_sidebar.elements.element2.id'), + icon: this.i18n.t('repositories.import_records.info_sidebar.elements.element2.icon'), + label: this.i18n.t('repositories.import_records.info_sidebar.elements.element2.label'), + subtext: this.i18n.t('repositories.import_records.info_sidebar.elements.element2.subtext') }, { - id: I18n.t('repositories.import_records.info_sidebar.elements.element3.id'), - icon: I18n.t('repositories.import_records.info_sidebar.elements.element3.icon'), - label: I18n.t('repositories.import_records.info_sidebar.elements.element3.label'), - subtext: I18n.t('repositories.import_records.info_sidebar.elements.element3.subtext') + id: this.i18n.t('repositories.import_records.info_sidebar.elements.element3.id'), + icon: this.i18n.t('repositories.import_records.info_sidebar.elements.element3.icon'), + label: this.i18n.t('repositories.import_records.info_sidebar.elements.element3.label'), + subtext: this.i18n.t('repositories.import_records.info_sidebar.elements.element3.subtext') }, { - id: I18n.t('repositories.import_records.info_sidebar.elements.element4.id'), - icon: I18n.t('repositories.import_records.info_sidebar.elements.element4.icon'), - label: I18n.t('repositories.import_records.info_sidebar.elements.element4.label'), - subtext: I18n.t('repositories.import_records.info_sidebar.elements.element4.subtext'), - linkTo: I18n.t('repositories.import_records.info_sidebar.elements.element4.linkTo') + id: this.i18n.t('repositories.import_records.info_sidebar.elements.element4.id'), + icon: this.i18n.t('repositories.import_records.info_sidebar.elements.element4.icon'), + label: this.i18n.t('repositories.import_records.info_sidebar.elements.element4.label'), + subtext: this.i18n.t('repositories.import_records.info_sidebar.elements.element4.subtext'), + linkTo: this.i18n.t('repositories.import_records.info_sidebar.elements.element4.linkTo') } ] - }, - stepData: null + } }; }, - watch: { - activeStep(newVal, oldVal) { - console.log(`${oldVal} -> ${newVal}`); - }, - stepData(newVal, oldVal) { - console.log(`${oldVal} -> ${newVal}`); - } - }, created() { window.importRepositoryModalComponent = this; }, - mounted() { - }, methods: { open() { this.$refs.modal.open(); }, - proceedToNext(data) { - console.log('incoming data', data); - this.stepData = data; + proceedToNextStep(data) { + this.steps[this.activeStep + 1].stepData = data; this.activeStep += 1; + }, + goBackToPrevStep() { + this.activeStep -= 1; } } }; diff --git a/app/javascript/vue/repositories/modals/import/first_step.vue b/app/javascript/vue/repositories/modals/import/first_step.vue index e0805a389..03fd68252 100644 --- a/app/javascript/vue/repositories/modals/import/first_step.vue +++ b/app/javascript/vue/repositories/modals/import/first_step.vue @@ -7,16 +7,16 @@

- {{ i18n.t('repositories.import_records.steps.step0.importTitle') }} + {{ i18n.t('repositories.import_records.steps.step1.importTitle') }}

@@ -24,13 +24,13 @@

- {{ i18n.t('repositories.import_records.steps.step0.importBtnText') }} + {{ i18n.t('repositories.import_records.steps.step1.importBtnText') }}

@@ -50,7 +50,7 @@
{{ exportInventoryMessage }}
@@ -62,10 +62,16 @@ import DragAndDropUpload from '../../../shared/drag_and_drop_upload.vue'; export default { name: 'FirstStep', - emits: ['step:next'], + emits: ['step:next', 'info:hide'], components: { DragAndDropUpload }, + props: { + stepProps: { + type: Object, + required: false + } + }, data() { return { showingInfo: false, @@ -136,14 +142,23 @@ export default { // First, parse the sheet const parsedSheetResponse = await this.parseSheet(file); - // If parsed successfully, go to next step and pass the necessary data + // If parsed successfully, go to next step and pass through the necessary data if (parsedSheetResponse) { const { header: columnNames, available_fields: availableFields, columns: exampleData } = parsedSheetResponse.data.import_data; - this.$emit('step:next', { columnNames, availableFields, exampleData }); + const fileName = file.name; + const tempFile = parsedSheetResponse.data.temp_file; + + this.$emit('step:next', { + columnNames, + availableFields, + exampleData, + fileName, + tempFile + }); } }, async parseSheet(file) { diff --git a/app/javascript/vue/repositories/modals/import/second_step.vue b/app/javascript/vue/repositories/modals/import/second_step.vue new file mode 100644 index 000000000..ae47fcbe4 --- /dev/null +++ b/app/javascript/vue/repositories/modals/import/second_step.vue @@ -0,0 +1,329 @@ + + + diff --git a/app/javascript/vue/repositories/modals/import/second_step_table_row.vue b/app/javascript/vue/repositories/modals/import/second_step_table_row.vue new file mode 100644 index 000000000..331894128 --- /dev/null +++ b/app/javascript/vue/repositories/modals/import/second_step_table_row.vue @@ -0,0 +1,117 @@ + + + diff --git a/app/javascript/vue/shared/info_modal.vue b/app/javascript/vue/shared/info_modal.vue index fd85cc38a..e249cdd0e 100644 --- a/app/javascript/vue/shared/info_modal.vue +++ b/app/javascript/vue/shared/info_modal.vue @@ -1,10 +1,10 @@