Adds duplication dialog and routine.

This commit is contained in:
Mateus Machado Luna 2019-07-18 14:50:30 -03:00
parent 61e597c6c8
commit 72388ecd14
10 changed files with 195 additions and 28 deletions

View File

@ -107,11 +107,11 @@
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode"> v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode">
{{ $i18n.getFrom('items','edit_item') }} {{ $i18n.getFrom('items','edit_item') }}
</b-dropdown-item> </b-dropdown-item>
<!-- <b-dropdown-item <b-dropdown-item
@click="duplicateOneItem(contextMenuItem.id)" @click="duplicateOneItem(contextMenuItem.id)"
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode"> v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode">
{{ $i18n.get('label_duplicate_item') }} {{ $i18n.get('label_duplicate_item') }}
</b-dropdown-item> --> </b-dropdown-item>
<b-dropdown-item <b-dropdown-item
@click="deleteOneItem(contextMenuItem.id)" @click="deleteOneItem(contextMenuItem.id)"
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode"> v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode">
@ -673,7 +673,7 @@
</div> </div>
</masonry> </masonry>
<!-- TABLE VIEW MODE --> <!-- TABLE VIEW MODE -->
<table <table
v-if="viewMode == 'table'" v-if="viewMode == 'table'"
@ -712,7 +712,10 @@
</thead> </thead>
<tbody> <tbody>
<tr <tr
:class="{ 'selected-row': selectedItems[index] }" :class="{
'selected-row': selectedItems[index],
'highlighted-item': highlightedItem == item.id
}"
:key="index" :key="index"
v-for="(item, index) of items"> v-for="(item, index) of items">
<!-- Checking list --> <!-- Checking list -->
@ -900,6 +903,7 @@
<script> <script>
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import CustomDialog from '../other/custom-dialog.vue'; import CustomDialog from '../other/custom-dialog.vue';
import DuplicationDialog from '../other/duplication-dialog.vue';
import BulkEditionModal from '../bulk-edition/bulk-edition-modal.vue'; import BulkEditionModal from '../bulk-edition/bulk-edition-modal.vue';
import { dateInter } from "../../../admin/js/mixins"; import { dateInter } from "../../../admin/js/mixins";
@ -939,6 +943,14 @@ export default {
this.selectedItemsIDs.push(false); this.selectedItemsIDs.push(false);
this.selectedItems.push(false); this.selectedItems.push(false);
} }
if (this.highlightsItem)
setTimeout(() => this.$eventBusSearch.highlightsItem(null), 3000);
},
computed: {
highlightedItem () {
return this.getHighlightedItem();
}
}, },
watch: { watch: {
selectedItems() { selectedItems() {
@ -972,18 +984,18 @@ export default {
'createEditGroup', 'createEditGroup',
'trashItemsInBulk', 'trashItemsInBulk',
'deleteItemsInBulk', 'deleteItemsInBulk',
'untrashItemsInBulk', 'untrashItemsInBulk'
]), ]),
...mapGetters('bulkedition', [ ...mapGetters('bulkedition', [
'getGroupID' 'getGroupID'
]), ]),
...mapActions('item', [ ...mapActions('item', [
'fetchItem', 'fetchItem'
'duplicateItem'
]), ]),
...mapGetters('search', [ ...mapGetters('search', [
'getOrder', 'getOrder',
'getOrderBy' 'getOrderBy',
'getHighlightedItem'
]), ]),
openBulkEditionModal(){ openBulkEditionModal(){
this.$modal.open({ this.$modal.open({
@ -1026,15 +1038,24 @@ export default {
} }
}, },
duplicateOneItem(itemId) { duplicateOneItem(itemId) {
this.fetchItem({ itemId: itemId, contextEdit: true })
.then((item) => { this.$modal.open({
this.duplicateItem({ item: item }) parent: this,
.then((duplicatedItem) => { component: DuplicationDialog,
this.$console.log(duplicatedItem); canCancel: false,
}) props: {
.catch((error) => this.$console.error(error)); icon: 'items',
}) collectionId: this.collectionId,
.catch(error => this.$console.error("Error fetching item for duplicate: " + error)); itemId: itemId,
onConfirm: (duplicatedItemId) => {
if (duplicatedItemId != null && duplicatedItemId != undefined)
this.$eventBusSearch.highlightsItem(duplicatedItemId);
this.$eventBusSearch.loadItems();
}
}
});
this.clearContextMenu(); this.clearContextMenu();
}, },
untrashOneItem(itemId) { untrashOneItem(itemId) {
@ -1278,6 +1299,23 @@ export default {
} }
} }
@keyframes highlight {
from {
background-color: $blue1;
}
to {
background-color: initial;
}
}
.highlighted-item {
transition: background-color 0.5s;
animation-name: highlight;
animation-duration: 1s;
animation-iteration-count: 2;
}
</style> </style>

View File

@ -525,7 +525,7 @@
.highlighted-process { .highlighted-process {
&>.process-handler { &>.process-handler {
transition: background-color 0.5s; transition: background-color 0.8s;
animation-name: highlight; animation-name: highlight;
animation-duration: 1s; animation-duration: 1s;
animation-iteration-count: 2; animation-iteration-count: 2;

View File

@ -0,0 +1,113 @@
<template>
<div
aria-labelledby="alert-dialog-title"
aria-modal="true"
role="alertdialog"
class="tainacan-form dialog">
<div
class="modal-card"
style="width: auto">
<div
v-if="icon != undefined && icon != ''"
class="modal-custom-icon">
<span class="icon is-large">
<i
:class="'tainacan-icon-' + icon"
class="tainacan-icon"/>
</span>
</div>
<section
tabindex="1"
class="modal-card-body">
<header
class="modal-card-head">
<h1
id="alert-dialog-title"
class="modal-card-title">
{{ $i18n.get('label_duplicating_item') }}
</h1>
</header>
{{ message }}
</section>
<footer class="modal-card-foot form-submit">
<button
type="submit"
class="button is-outlined"
:disabled="isLoading"
@click="onConfirm(duplicatedItemId); $parent.close();">
{{ $i18n.get('label_items_list') }}
</button>
<button
type="submit"
class="button is-success"
:disabled="isLoading"
@click="$router.push($routerHelper.getItemEditPath(collectionId, duplicatedItemId)); $parent.close();">
{{ $i18n.getFrom('items','edit_item') }}
</button>
</footer>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
name: 'DuplicationDialog',
props: {
icon: String,
onConfirm: {
type: Function,
default: () => {}
},
collectionId: String,
itemId: String
},
data() {
return {
isLoading: Boolean,
message: String,
duplicatedItemId: String
}
},
methods: {
...mapActions('item', [
'fetchItem',
'duplicateItem'
]),
},
created() {
this.isLoading = true;
this.message = this.$i18n.get('info_await_while_item_duplication');
this.duplicateItem({ collectionId: this.collectionId, itemId: this.itemId })
.then((duplicatedItem) => {
this.isLoading = false;
this.message = this.$i18n.get('label_item_duplication_success');
this.duplicatedItemId = duplicatedItem.id;
})
.catch((error) => {
this.$console.error('Error fetching item for duplicate ' + error);
this.isLoading = false;
this.message = this.$i18n.get('label_item_duplication_failure');
});
}
}
</script>
<style scoped>
i.tainacan-icon,
i.tainacan-icon::before {
font-size: 42px;
}
button.is-success {
margin-left: auto;
}
.modal-card-foot {
margin-top: 12px;
}
</style>

View File

@ -415,6 +415,9 @@ return apply_filters( 'tainacan-admin-i18n', [
'label_duplicate_item' => __( 'Duplicate item', 'tainacan' ), 'label_duplicate_item' => __( 'Duplicate item', 'tainacan' ),
'label_create_another_item' => __( 'Create another item', 'tainacan' ), 'label_create_another_item' => __( 'Create another item', 'tainacan' ),
'label_recent_collections' => __( 'Recent Collections', 'tainacan' ), 'label_recent_collections' => __( 'Recent Collections', 'tainacan' ),
'label_duplicating_item' => __( 'Duplicating item', 'tainacan' ),
'label_item_duplication_success' => __( 'The item was duplicated with success!', 'tainacan' ),
'label_item_duplication_failure' => __( 'Something wrong happened... Item duplication failed!', 'tainacan' ),
// Instructions. More complex sentences to guide user and placeholders // Instructions. More complex sentences to guide user and placeholders
'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ), 'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ),
@ -625,8 +628,9 @@ return apply_filters( 'tainacan-admin-i18n', [
'info_send_email' => __('The exporter may take a while. Check this option to receive an e-mail when the process is done. You can also check the process status visiting the', 'tainacan'), 'info_send_email' => __('The exporter may take a while. Check this option to receive an e-mail when the process is done. You can also check the process status visiting the', 'tainacan'),
'info_tainacan_api' => __('Tainacan API on JSON format.', 'tainacan'), 'info_tainacan_api' => __('Tainacan API on JSON format.', 'tainacan'),
'info_items_hidden_due_sorting' => __('When ordering by metadata value, items that have no value for the chosen metadata will not be listed. This list may have less elements than the total existing for current search criteria.', 'tainacan'), 'info_items_hidden_due_sorting' => __('When ordering by metadata value, items that have no value for the chosen metadata will not be listed. This list may have less elements than the total existing for current search criteria.', 'tainacan'),
'info_sorting_by_metadata_value_%s' => __('Showing only items that have value for metadata %s.'), 'info_sorting_by_metadata_value_%s' => __('Showing only items that have value for metadata %s.', 'tainacan'),
'info_sorting_by_metadata_value_%s_empty_list' => __('No item found, but only items with values for metadata %s are shown. Try sorting by other metatada.'), 'info_sorting_by_metadata_value_%s_empty_list' => __('No item found, but only items with values for metadata %s are shown. Try sorting by other metatada.', 'tainacan'),
'info_await_while_item_duplication' => __('Please wait while item is being duplicated...', 'tainacan'),
// Tainacan Metadatum Types // Tainacan Metadatum Types
'tainacan-text' => __( 'Text', 'tainacan' ), 'tainacan-text' => __( 'Text', 'tainacan' ),

View File

@ -303,6 +303,9 @@ export default {
this.$store.dispatch('search/setAdminViewMode', adminViewMode); this.$store.dispatch('search/setAdminViewMode', adminViewMode);
this.updateURLQueries(); this.updateURLQueries();
}, },
highlightsItem(itemId) {
this.$store.dispatch('search/highlightsItem', itemId);
},
updateURLQueries() { updateURLQueries() {
this.$router.replace({ query: {} }); this.$router.replace({ query: {} });
this.$router.replace({ query: this.$store.getters['search/getPostQuery'] }); this.$router.replace({ query: this.$store.getters['search/getPostQuery'] });

View File

@ -134,14 +134,10 @@ export const updateItem = ({ commit }, item) => {
}); });
}; };
export const duplicateItem = ({ commit }, { item, attachment }) => { export const duplicateItem = ({ commit }, { collectionId, itemId }) => {
delete item['id'];
if (item['terms'] == null)
item['terms'] = [];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacan.post('/collection/' + item.collection_id + '/items/', item) axios.tainacan.post('/collection/' + collectionId + '/items/' + itemId + '/duplicate')
.then( res => { .then( res => {
resolve( res.data ); resolve( res.data );
}).catch( error => { }).catch( error => {

View File

@ -165,4 +165,8 @@ export const cleanTaxQueries = ({ commit }) => {
export const cleanFetchOnly = ({ commit }) => { export const cleanFetchOnly = ({ commit }) => {
commit('cleanFetchOnly'); commit('cleanFetchOnly');
};
export const highlightsItem = ({ commit }, itemId ) => {
commit('setHighlightedItem', itemId);
}; };

View File

@ -83,3 +83,7 @@ export const getFilterTags = state => {
export const getFacets = state => { export const getFacets = state => {
return state.facets; return state.facets;
}; };
export const getHighlightedItem = state => {
return state.highlightedItem;
};

View File

@ -23,7 +23,8 @@ const state = {
totalPages: 0, totalPages: 0,
itemsPerPage: 12, // Not the same as postquery.perpage as API may have limited it's value itemsPerPage: 12, // Not the same as postquery.perpage as API may have limited it's value
facets: {}, facets: {},
orderByName: '' orderByName: '',
highlightedItem: null
}; };
export default { export default {

View File

@ -187,4 +187,8 @@ export const cleanFetchOnly = (state) => {
export const setFacets = (state, facets) => { export const setFacets = (state, facets) => {
state.facets = facets; state.facets = facets;
} }
export const setHighlightedItem = (state, itemId) => {
state.highlightedItem = itemId;
}