feat: Add possibility to clone cards when cloning a board
Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Adjust BoardServiceTest to new dependencies Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Add BoardCloneModal vue component to frontend. Adjust BoardApi and store to support clone options Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Add license and credits Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Fix PHP code style Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Change default clone settings Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Add accordion for advanced settings Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Fix bug which caused board to be cloned when clicking out of the modal Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> Change wording of clone options Signed-off-by: Max Bachhuber <max.bachhuber@bahuma.io> fix: Rebase failures Signed-off-by: Julius Härtl <jus@bitgrid.net> update cloneBoards phpdoc make error message clear SPDX Header BoardCloneModal.vue Signed-off-by: grnd-alt <salimbelakkaf@outlook.de>
This commit is contained in:
committed by
Julius Knorr
parent
bdaf28eef4
commit
f2c30afe8a
@@ -12,7 +12,10 @@
|
||||
:force-display-actions="isTouchDevice"
|
||||
@click="onNavigate"
|
||||
@undo="unDelete">
|
||||
<NcAppNavigationIconBullet slot="icon" :color="board.color" />
|
||||
<template #icon>
|
||||
<NcAppNavigationIconBullet :color="board.color" />
|
||||
<BoardCloneModal v-if="cloneModalOpen" :board-title="board.title" @close="onCloseCloneModal" />
|
||||
</template>
|
||||
|
||||
<template #counter>
|
||||
<AccountIcon v-if="board.acl.length > 0" />
|
||||
@@ -33,7 +36,7 @@
|
||||
</NcActionButton>
|
||||
<NcActionButton v-if="canCreate && !board.archived"
|
||||
:close-after-click="true"
|
||||
@click="actionClone">
|
||||
@click="showCloneModal">
|
||||
<template #icon>
|
||||
<CloneIcon :size="20" decorative />
|
||||
</template>
|
||||
@@ -157,6 +160,7 @@ import { loadState } from '@nextcloud/initial-state'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
|
||||
import isTouchDevice from '../../mixins/isTouchDevice.js'
|
||||
import BoardCloneModal from './BoardCloneModal.vue'
|
||||
|
||||
const canCreateState = loadState('deck', 'canCreate')
|
||||
|
||||
@@ -174,6 +178,7 @@ export default {
|
||||
CloneIcon,
|
||||
CloseIcon,
|
||||
CheckIcon,
|
||||
BoardCloneModal,
|
||||
},
|
||||
directives: {
|
||||
ClickOutside,
|
||||
@@ -201,6 +206,7 @@ export default {
|
||||
isDueSubmenuActive: false,
|
||||
updateDueSetting: null,
|
||||
canCreate: canCreateState,
|
||||
cloneModalOpen: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -349,6 +355,26 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
showCloneModal() {
|
||||
this.cloneModalOpen = true
|
||||
},
|
||||
async onCloseCloneModal(data) {
|
||||
this.cloneModalOpen = false
|
||||
if (data) {
|
||||
this.loading = true
|
||||
try {
|
||||
const newBoard = await this.$store.dispatch('cloneBoard', {
|
||||
boardData: this.board,
|
||||
settings: data,
|
||||
})
|
||||
this.loading = false
|
||||
this.$router.push({ name: 'board', params: { id: newBoard.id } })
|
||||
} catch (e) {
|
||||
OC.Notification.showTemporary(t('deck', 'An error occurred'))
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
124
src/components/navigation/BoardCloneModal.vue
Normal file
124
src/components/navigation/BoardCloneModal.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<!--
|
||||
- SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
<template>
|
||||
<NcDialog :name="t('deck', 'Clone {boardTitle}', {boardTitle: boardTitle})" :show="true" @close="close(false)">
|
||||
<div class="modal__content">
|
||||
<NcCheckboxRadioSwitch :checked.sync="withCards">
|
||||
{{ t('deck', 'Clone cards') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<NcCheckboxRadioSwitch v-if="withCards" :checked.sync="withAssignments">
|
||||
{{ t('deck', 'Clone assignments') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<NcCheckboxRadioSwitch v-if="withCards" :checked.sync="withLabels">
|
||||
{{ t('deck', 'Clone labels') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<NcCheckboxRadioSwitch v-if="withCards" :checked.sync="withDueDate">
|
||||
{{ t('deck', 'Clone due dates') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<div v-if="withCards" class="accordion" :class="{ 'is-open': accordionOpen }">
|
||||
<div class="accordion__toggle" @click="accordionOpen = !accordionOpen">
|
||||
<span class="accordion__toggle__icon">
|
||||
‣
|
||||
</span>
|
||||
{{ t('deck', 'Advanced options') }}
|
||||
</div>
|
||||
<div v-if="accordionOpen" class="accordion__content">
|
||||
<NcCheckboxRadioSwitch v-if="withCards" :checked.sync="moveCardsToLeftStack">
|
||||
{{ t('deck', 'Move all cards to the first list') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<NcCheckboxRadioSwitch v-if="withCards" :checked.sync="restoreArchivedCards">
|
||||
{{ t('deck', 'Restore archived cards') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
<NcButton @click="cancel">
|
||||
{{ t('deck', 'Cancel') }}
|
||||
</NcButton>
|
||||
<NcButton type="primary" @click="save">
|
||||
{{ t('deck', 'Clone') }}
|
||||
</NcButton>
|
||||
</template>
|
||||
</NcDialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NcButton, NcCheckboxRadioSwitch, NcDialog } from '@nextcloud/vue'
|
||||
|
||||
export default {
|
||||
name: 'BoardCloneModal',
|
||||
components: {
|
||||
NcDialog,
|
||||
NcCheckboxRadioSwitch,
|
||||
NcButton,
|
||||
},
|
||||
props: {
|
||||
boardTitle: {
|
||||
type: String,
|
||||
default: 'Board',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
withCards: false,
|
||||
withAssignments: true,
|
||||
withLabels: true,
|
||||
withDueDate: true,
|
||||
moveCardsToLeftStack: false,
|
||||
restoreArchivedCards: false,
|
||||
accordionOpen: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close(data) {
|
||||
this.$emit('close', data)
|
||||
},
|
||||
save() {
|
||||
const data = {
|
||||
withCards: this.withCards,
|
||||
withAssignments: this.withAssignments,
|
||||
withLabels: this.withLabels,
|
||||
withDueDate: this.withDueDate,
|
||||
moveCardsToLeftStack: this.moveCardsToLeftStack,
|
||||
restoreArchivedCards: this.restoreArchivedCards,
|
||||
}
|
||||
this.close(data)
|
||||
},
|
||||
cancel() {
|
||||
this.close(false)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal__content {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.modal__title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal__buttons {
|
||||
text-align: end;
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.accordion__toggle {
|
||||
margin: .5em 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.accordion__toggle__icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.accordion.is-open .accordion__toggle__icon {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
</style>
|
||||
@@ -123,9 +123,16 @@ export class BoardApi {
|
||||
})
|
||||
}
|
||||
|
||||
async cloneBoard(board) {
|
||||
async cloneBoard(board, withCards = false, withAssignments = false, withLabels = false, withDueDate = false, moveCardsToLeftStack = false, restoreArchivedCards = false) {
|
||||
try {
|
||||
const response = await axios.post(this.url(`/boards/${board.id}/clone`))
|
||||
const response = await axios.post(this.url(`/boards/${board.id}/clone`), {
|
||||
withCards,
|
||||
withAssignments,
|
||||
withLabels,
|
||||
withDueDate,
|
||||
moveCardsToLeftStack,
|
||||
restoreArchivedCards,
|
||||
})
|
||||
return response.data
|
||||
} catch (err) {
|
||||
return err
|
||||
|
||||
@@ -398,9 +398,11 @@ export default new Vuex.Store({
|
||||
return err
|
||||
}
|
||||
},
|
||||
async cloneBoard({ commit }, boardData) {
|
||||
async cloneBoard({ commit }, { boardData, settings }) {
|
||||
const { withCards, withAssignments, withLabels, withDueDate, moveCardsToLeftStack, restoreArchivedCards } = settings
|
||||
|
||||
try {
|
||||
const newBoard = await apiClient.cloneBoard(boardData)
|
||||
const newBoard = await apiClient.cloneBoard(boardData, withCards, withAssignments, withLabels, withDueDate, moveCardsToLeftStack, restoreArchivedCards)
|
||||
commit('cloneBoard', newBoard)
|
||||
return newBoard
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user