mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-10 07:05:57 +08:00
Add preview step and success step [SCI-9851]
This commit is contained in:
parent
7d2f6238de
commit
5e8cf6a221
13 changed files with 272 additions and 16 deletions
|
@ -227,6 +227,11 @@ GEM
|
|||
mail
|
||||
case_transform (0.2)
|
||||
activesupport
|
||||
caxlsx (4.0.0)
|
||||
htmlentities (~> 4.3, >= 4.3.4)
|
||||
marcel (~> 1.0)
|
||||
nokogiri (~> 1.10, >= 1.10.4)
|
||||
rubyzip (>= 1.3.0, < 3)
|
||||
cgi (0.4.1)
|
||||
childprocess (4.1.0)
|
||||
chunky_png (1.4.0)
|
||||
|
@ -353,6 +358,7 @@ GEM
|
|||
nokogiri (~> 1.0)
|
||||
hashdiff (1.0.1)
|
||||
hashie (5.0.0)
|
||||
htmlentities (4.3.4)
|
||||
http (5.1.1)
|
||||
addressable (~> 2.8)
|
||||
http-cookie (~> 1.0)
|
||||
|
@ -731,13 +737,13 @@ GEM
|
|||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (2.4.2)
|
||||
uniform_notifier (1.16.0)
|
||||
uri (0.13.0)
|
||||
validate_email (0.1.6)
|
||||
activemodel (>= 3.0)
|
||||
mail (>= 2.2.5)
|
||||
validate_url (1.0.15)
|
||||
activemodel (>= 3.0.0)
|
||||
public_suffix
|
||||
uri (0.13.0)
|
||||
version_gem (1.1.3)
|
||||
view_component (3.9.0)
|
||||
activesupport (>= 5.2.0, < 8.0)
|
||||
|
@ -795,6 +801,7 @@ DEPENDENCIES
|
|||
capybara
|
||||
capybara-email
|
||||
caracal!
|
||||
caxlsx
|
||||
cssbundling-rails
|
||||
cucumber-rails
|
||||
database_cleaner
|
||||
|
|
|
@ -6,20 +6,31 @@
|
|||
:uploading="uploading"
|
||||
@uploadFile="uploadFile"
|
||||
@generatePreview="generatePreview"
|
||||
@changeStep="changeStep"
|
||||
@importRows="importRecords"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global HelperModule */
|
||||
|
||||
import axios from '../../../../packs/custom_axios';
|
||||
import InfoModal from '../../../shared/info_modal.vue';
|
||||
import UploadStep from './upload_step.vue';
|
||||
import MappingStep from './mapping_step.vue';
|
||||
import PreviewStep from './preview_step.vue';
|
||||
import SuccessStep from './success_step.vue';
|
||||
|
||||
export default {
|
||||
name: 'ImportRepositoryModal',
|
||||
components: { InfoModal, UploadStep, MappingStep },
|
||||
components: {
|
||||
InfoModal,
|
||||
UploadStep,
|
||||
MappingStep,
|
||||
PreviewStep,
|
||||
SuccessStep
|
||||
},
|
||||
props: {
|
||||
repositoryUrl: String,
|
||||
required: true
|
||||
|
@ -70,8 +81,10 @@ export default {
|
|||
this.params.onlyAddNewItems = onlyAddNewItems;
|
||||
this.importRecords(true);
|
||||
},
|
||||
|
||||
importRecords(preview = false) {
|
||||
changeStep(step) {
|
||||
this.activeStep = step;
|
||||
},
|
||||
importRecords(preview) {
|
||||
const jsonData = {
|
||||
file_id: this.params.temp_file.id,
|
||||
mappings: this.params.mapping,
|
||||
|
@ -80,7 +93,16 @@ export default {
|
|||
should_overwrite_with_empty_cells: this.params.updateWithEmptyCells,
|
||||
can_edit_existing_items: !this.params.onlyAddNewItems
|
||||
};
|
||||
axios.post(this.params.attributes.urls.import_records, jsonData);
|
||||
axios.post(this.params.attributes.urls.import_records, jsonData)
|
||||
.then((response) => {
|
||||
if (preview) {
|
||||
this.params.preview = response.data.changes;
|
||||
this.params.import_date = response.data.import_date;
|
||||
this.activeStep = 'PreviewStep';
|
||||
} else {
|
||||
this.activeStep = 'SuccessStep';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
:params="params"
|
||||
:selected="this.selectedItemsIndexes.includes(index)"
|
||||
@selection:changed="handleChange"
|
||||
:availableFields="this.availableFields"
|
||||
:autoMapping="this.autoMapping"
|
||||
/>
|
||||
</template>
|
||||
|
@ -94,7 +93,7 @@ import modalMixin from '../../../shared/modal_mixin';
|
|||
|
||||
export default {
|
||||
name: 'MappingStep',
|
||||
emits: ['step:next'],
|
||||
emits: ['close', 'generatePreview'],
|
||||
mixins: [modalMixin],
|
||||
components: {
|
||||
SelectDropdown,
|
||||
|
@ -104,7 +103,7 @@ export default {
|
|||
params: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
v-else
|
||||
:options="dropdownOptions"
|
||||
@change="changeSelected"
|
||||
@isOpen="handleIsOpen"
|
||||
:clearable="true"
|
||||
:size="'sm'"
|
||||
:placeholder="computeMatchNotFound ?
|
||||
|
|
147
app/javascript/vue/repositories/modals/import/preview_step.vue
Normal file
147
app/javascript/vue/repositories/modals/import/preview_step.vue
Normal file
|
@ -0,0 +1,147 @@
|
|||
<template>
|
||||
<div ref="modal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content grow">
|
||||
<div class="modal-header gap-4">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-e2e="e2e-BT-newInventoryModal-close">
|
||||
<i class="sn-icon sn-icon-close"></i>
|
||||
</button>
|
||||
<h4 class="modal-title truncate !block" id="edit-project-modal-label" data-e2e="e2e-TX-newInventoryModal-title">
|
||||
{{ i18n.t('repositories.import_records.steps.step3.title') }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-sn-dark-grey mb-6">
|
||||
{{ i18n.t('repositories.import_records.steps.step3.subtitle', { inventory: params.attributes.name }) }}
|
||||
</p>
|
||||
<div class="flex items-center justify-between text-sn-dark-gray text-sm">
|
||||
<div>
|
||||
<div v-html="i18n.t('repositories.import_records.steps.step3.updated_items')"></div>
|
||||
<hr class="my-1">
|
||||
<h2 class="m-0 text-sn-alert-green">0</h2>
|
||||
</div>
|
||||
<div>
|
||||
<div v-html="i18n.t('repositories.import_records.steps.step3.new_items')"></div>
|
||||
<hr class="my-1">
|
||||
<h2 class="m-0 text-sn-alert-green">0</h2>
|
||||
</div>
|
||||
<div>
|
||||
<div v-html="i18n.t('repositories.import_records.steps.step3.unchanged_items')"></div>
|
||||
<hr class="my-1">
|
||||
<h2 class="m-0 ">0</h2>
|
||||
</div>
|
||||
<div>
|
||||
<div v-html="i18n.t('repositories.import_records.steps.step3.duplicated_items')"></div>
|
||||
<hr class="my-1">
|
||||
<h2 class="m-0 ">0</h2>
|
||||
</div>
|
||||
<div>
|
||||
<div v-html="i18n.t('repositories.import_records.steps.step3.invalid_items')"></div>
|
||||
<hr class="my-1">
|
||||
<h2 class="m-0 text-sn-alert-passion">0</h2>
|
||||
</div>
|
||||
<div>
|
||||
<div v-html="i18n.t('repositories.import_records.steps.step3.invalid_items')"></div>
|
||||
<hr class="my-1">
|
||||
<h2 class="m-0 text-sn-alert-passion">0</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-6">
|
||||
{{ i18n.t('repositories.import_records.steps.step2.importedFileText') }} {{ params.file_name }}
|
||||
</div>
|
||||
<div class="h-80">
|
||||
<ag-grid-vue
|
||||
class="ag-theme-alpine w-full flex-grow h-full z-10"
|
||||
:columnDefs="columnDefs"
|
||||
:defaultColDef="{
|
||||
resizable: true,
|
||||
sortable: false,
|
||||
suppressMovable: true
|
||||
}"
|
||||
:rowData="tableData"
|
||||
:suppressRowTransform="true"
|
||||
:suppressRowClickSelection="true"
|
||||
:enableCellTextSelection="true"
|
||||
></ag-grid-vue>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" @click="$emit('changeStep', 'MappingStep')">
|
||||
{{ i18n.t('repositories.import_records.steps.step3.cancel') }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" @click="$emit('importRows')">
|
||||
{{ i18n.t('repositories.import_records.steps.step3.confirm') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { AgGridVue } from 'ag-grid-vue3';
|
||||
import modalMixin from '../../../shared/modal_mixin';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'PreviewStep',
|
||||
mixins: [modalMixin],
|
||||
props: {
|
||||
params: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AgGridVue
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
columnDefs() {
|
||||
const columns = [
|
||||
{
|
||||
field: 'code',
|
||||
headerName: this.i18n.t('repositories.import_records.steps.step3.code')
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
headerName: this.i18n.t('repositories.import_records.steps.step3.name')
|
||||
}
|
||||
];
|
||||
|
||||
this.params.attributes.repository_columns.forEach((col) => {
|
||||
columns.push({
|
||||
field: `col_${col[0]}`,
|
||||
headerName: col[1]
|
||||
});
|
||||
});
|
||||
|
||||
columns.push({
|
||||
field: 'status',
|
||||
headerName: this.i18n.t('repositories.import_records.steps.step3.status'),
|
||||
pinned: 'right'
|
||||
});
|
||||
|
||||
return columns;
|
||||
},
|
||||
tableData() {
|
||||
const data = this.params.preview.data.map((row) => {
|
||||
const rowFormated = row.attributes;
|
||||
row.relationships.repository_cells.data.forEach((c) => {
|
||||
const cell = this.params.preview.included.find((c1) => c1.id === c.id);
|
||||
if (cell) {
|
||||
rowFormated[`col_${cell.attributes.repository_column_id}`] = cell.attributes.formatted_value;
|
||||
}
|
||||
});
|
||||
return rowFormated;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<div ref="modal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-sm" role="document">
|
||||
<div class="modal-content grow">
|
||||
<div class="modal-header gap-4">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-e2e="e2e-BT-newInventoryModal-close">
|
||||
<i class="sn-icon sn-icon-close"></i>
|
||||
</button>
|
||||
<h4 class="modal-title truncate !block" id="edit-project-modal-label" data-e2e="e2e-TX-newInventoryModal-title">
|
||||
{{ i18n.t('repositories.import_records.steps.step4.title') }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-sn-dark-grey mb-6">
|
||||
{{ i18n.t('repositories.import_records.steps.step4.subtitle', { inventory: params.attributes.name }) }}
|
||||
</p>
|
||||
<div>
|
||||
<b>{{ i18n.t('repositories.import_records.steps.step4.import_date') }}</b>
|
||||
{{ params.import_date }}
|
||||
</div>
|
||||
<div>
|
||||
<b>{{ i18n.t('repositories.import_records.steps.step4.imported_file') }}</b>
|
||||
{{ params.file_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" >
|
||||
{{ i18n.t('repositories.import_records.steps.step4.download_report') }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" @click="close">
|
||||
{{ i18n.t('repositories.import_records.steps.step4.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modalMixin from '../../../shared/modal_mixin';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'SuccessStep',
|
||||
mixins: [modalMixin],
|
||||
props: {
|
||||
params: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -91,7 +91,7 @@ import modalMixin from '../../../shared/modal_mixin';
|
|||
|
||||
export default {
|
||||
name: 'UploadStep',
|
||||
emits: ['step:next', 'info:hide'],
|
||||
emits: ['uploadFile'],
|
||||
components: {
|
||||
DragAndDropUpload
|
||||
},
|
||||
|
@ -123,6 +123,9 @@ export default {
|
|||
},
|
||||
uploadFile(file) {
|
||||
this.$emit('uploadFile', file);
|
||||
},
|
||||
handleError(error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class RepositoryCellSerializer < ActiveModel::Serializer
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
attributes :id, :value, :changes
|
||||
attributes :id, :value, :changes, :repository_column_id, :formatted_value
|
||||
|
||||
def changes
|
||||
object.value.changes
|
||||
|
@ -12,4 +12,8 @@ class RepositoryCellSerializer < ActiveModel::Serializer
|
|||
def value
|
||||
object.value
|
||||
end
|
||||
|
||||
def formatted_value
|
||||
object.value.formatted
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,5 +4,6 @@ class RepositoryRowSerializer < ActiveModel::Serializer
|
|||
include Rails.application.routes.url_helpers
|
||||
|
||||
attributes :id, :name, :code
|
||||
has_many :repository_cells
|
||||
|
||||
has_many :repository_cells, serializer: RepositoryCellSerializer
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class RepositorySerializer < ActiveModel::Serializer
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
attributes :urls, :id, :team_id, :repository_columns
|
||||
attributes :urls, :id, :team_id, :repository_columns, :name
|
||||
|
||||
def repository_columns
|
||||
object.repository_columns.pluck(:id, :name, :data_type)
|
||||
|
|
|
@ -10,7 +10,7 @@ module ImportRepository
|
|||
|
||||
def import!(can_edit_existing_items, should_overwrite_with_empty_cells, preview)
|
||||
status = run_import_actions(can_edit_existing_items, should_overwrite_with_empty_cells, preview)
|
||||
@temp_file.destroy
|
||||
#@temp_file.destroy
|
||||
status
|
||||
end
|
||||
|
||||
|
|
|
@ -166,9 +166,9 @@ module RepositoryImportParser
|
|||
imported_rows,
|
||||
each_serializer: RepositoryRowSerializer,
|
||||
include: [:repository_cells]
|
||||
).as_json[:included]
|
||||
).as_json
|
||||
|
||||
{ status: :ok, nr_of_added: @new_rows_added, total_nr: @total_new_rows, changes: changes }
|
||||
{ status: :ok, nr_of_added: @new_rows_added, total_nr: @total_new_rows, changes: changes, import_date: I18n.l(Date.today, format: :full_date) }
|
||||
end
|
||||
|
||||
def import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells, preview)
|
||||
|
|
|
@ -2264,6 +2264,27 @@ en:
|
|||
scinoteColumns: 'SciNote columns'
|
||||
status: 'Status'
|
||||
exampleData: 'Example data'
|
||||
step3:
|
||||
title: 'Import preview'
|
||||
subtitle: 'This is a preview of items you are importing/updating to the %{inventory}. The import can still be canceled.'
|
||||
updated_items: 'Updated<br>items'
|
||||
new_items: 'New<br>items'
|
||||
unchanged_items: 'Unchanged<br>items'
|
||||
duplicated_items: 'Duplicated<br>items'
|
||||
invalid_items: 'Invalid<br>items'
|
||||
invalid_cells: 'Invalid<br>cells'
|
||||
code: 'Code'
|
||||
name: 'Name'
|
||||
status: 'Status'
|
||||
cancel: 'Cancel import'
|
||||
confirm: 'Confirm'
|
||||
step4:
|
||||
title: 'Success report'
|
||||
subtitle: '%{inventory} was successfully updated.'
|
||||
import_date: 'Import date:'
|
||||
imported_file: 'Imported file:'
|
||||
download_report: 'Download success report'
|
||||
close: 'Close'
|
||||
info_sidebar:
|
||||
title: 'Guide for updating the inventory'
|
||||
elements:
|
||||
|
|
Loading…
Add table
Reference in a new issue