show menu in compact mode
Signed-off-by: Jakob Röhrl <jakob.roehrl@web.de>
This commit is contained in:
committed by
Julius Härtl
parent
042ae2bc3c
commit
78f38b2d94
@@ -34,141 +34,32 @@
|
|||||||
|
|
||||||
<AvatarList :users="card.assignedUsers" />
|
<AvatarList :users="card.assignedUsers" />
|
||||||
|
|
||||||
<div @click.stop.prevent>
|
<CardMenu :id="id" />
|
||||||
<Actions v-if="canEdit">
|
|
||||||
<ActionButton v-if="showArchived === false" icon="icon-user" @click="assignCardToMe()">
|
|
||||||
{{ t('deck', 'Assign to me') }}
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton icon="icon-archive" @click="archiveUnarchiveCard()">
|
|
||||||
{{ t('deck', (showArchived ? 'Unarchive card' : 'Archive card')) }}
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton v-if="showArchived === false" icon="icon-delete" @click="deleteCard()">
|
|
||||||
{{ t('deck', 'Delete card') }}
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton icon="icon-external" @click.stop="modalShow=true">
|
|
||||||
{{ t('deck', 'Move card') }}
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton icon="icon-settings-dark" @click="openCard">
|
|
||||||
{{ t('deck', 'Card details') }}
|
|
||||||
</ActionButton>
|
|
||||||
</Actions>
|
|
||||||
</div>
|
|
||||||
<Modal v-if="modalShow" :title="t('deck', 'Move card to another board')" @close="modalShow=false">
|
|
||||||
<div class="modal__content">
|
|
||||||
<h3>{{ t('deck', 'Move card to another board') }}</h3>
|
|
||||||
<Multiselect v-model="selectedBoard"
|
|
||||||
:placeholder="t('deck', 'Select a board')"
|
|
||||||
:options="boards"
|
|
||||||
:max-height="100"
|
|
||||||
label="title"
|
|
||||||
@select="loadStacksFromBoard" />
|
|
||||||
<Multiselect v-model="selectedStack"
|
|
||||||
:placeholder="t('deck', 'Select a stack')"
|
|
||||||
:options="stacksFromBoard"
|
|
||||||
:max-height="100"
|
|
||||||
label="title" />
|
|
||||||
|
|
||||||
<button :disabled="!isBoardAndStackChoosen" class="primary" @click="moveCard">
|
|
||||||
{{ t('deck', 'Move card') }}
|
|
||||||
</button>
|
|
||||||
<button @click="modalShow=false">
|
|
||||||
{{ t('deck', 'Cancel') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import AvatarList from './AvatarList'
|
import AvatarList from './AvatarList'
|
||||||
import { Modal, Actions, ActionButton, Multiselect } from '@nextcloud/vue'
|
import CardMenu from './CardMenu'
|
||||||
import { mapGetters, mapState } from 'vuex'
|
|
||||||
import axios from '@nextcloud/axios'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CardBadges',
|
name: 'CardBadges',
|
||||||
components: { AvatarList, Actions, ActionButton, Modal, Multiselect },
|
components: { AvatarList, CardMenu },
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
modalShow: false,
|
|
||||||
selectedBoard: '',
|
|
||||||
selectedStack: '',
|
|
||||||
stacksFromBoard: [],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
|
||||||
'canEdit',
|
|
||||||
]),
|
|
||||||
...mapState({
|
|
||||||
showArchived: state => state.showArchived,
|
|
||||||
currentBoard: state => state.currentBoard,
|
|
||||||
}),
|
|
||||||
checkListCount() {
|
checkListCount() {
|
||||||
return (this.card.description.match(/^\s*(\*|-|(\d\.))\s+\[\s*(\s|x)\s*\](.*)$/gim) || []).length
|
return (this.card.description.match(/^\s*(\*|-|(\d\.))\s+\[\s*(\s|x)\s*\](.*)$/gim) || []).length
|
||||||
},
|
},
|
||||||
checkListCheckedCount() {
|
checkListCheckedCount() {
|
||||||
return (this.card.description.match(/^\s*(\*|-|(\d\.))\s+\[\s*x\s*\](.*)$/gim) || []).length
|
return (this.card.description.match(/^\s*(\*|-|(\d\.))\s+\[\s*x\s*\](.*)$/gim) || []).length
|
||||||
},
|
},
|
||||||
compactMode() {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
card() {
|
card() {
|
||||||
return this.$store.getters.cardById(this.id)
|
return this.$store.getters.cardById(this.id)
|
||||||
},
|
},
|
||||||
isBoardAndStackChoosen() {
|
|
||||||
if (this.selectedBoard === '' || this.selectedStack === '') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
boards() {
|
|
||||||
return this.$store.getters.boards.filter(board => {
|
|
||||||
return board.id !== this.currentBoard.id
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
openCard() {
|
|
||||||
this.$router.push({ name: 'card', params: { cardId: this.id } })
|
|
||||||
},
|
|
||||||
deleteCard() {
|
|
||||||
this.$store.dispatch('deleteCard', this.card)
|
|
||||||
},
|
|
||||||
archiveUnarchiveCard() {
|
|
||||||
this.$store.dispatch('archiveUnarchiveCard', { ...this.card, archived: !this.card.archived })
|
|
||||||
},
|
|
||||||
assignCardToMe() {
|
|
||||||
this.copiedCard = Object.assign({}, this.card)
|
|
||||||
this.$store.dispatch('assignCardToUser', {
|
|
||||||
card: this.copiedCard,
|
|
||||||
assignee: {
|
|
||||||
userId: OC.getCurrentUser().uid,
|
|
||||||
type: 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
moveCard() {
|
|
||||||
this.copiedCard = Object.assign({}, this.card)
|
|
||||||
this.copiedCard.stackId = this.selectedStack.id
|
|
||||||
this.$store.dispatch('moveCard', this.copiedCard)
|
|
||||||
this.modalShow = false
|
|
||||||
},
|
|
||||||
async loadStacksFromBoard(board) {
|
|
||||||
try {
|
|
||||||
console.debug(board)
|
|
||||||
const url = OC.generateUrl('/apps/deck/stacks/' + board.id)
|
|
||||||
const response = await axios.get(url)
|
|
||||||
this.stacksFromBoard = response.data
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -239,21 +130,4 @@ export default {
|
|||||||
.fade-enter, .fade-leave-to {
|
.fade-enter, .fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal__content {
|
|
||||||
width: 25vw;
|
|
||||||
min-width: 250px;
|
|
||||||
min-height: 120px;
|
|
||||||
text-align: center;
|
|
||||||
margin: 20px 20px 100px 20px;
|
|
||||||
|
|
||||||
.multiselect {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal__content button {
|
|
||||||
float: right;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -54,6 +54,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<CardMenu v-if="!editing && compactMode" :id="id" class="right" />
|
||||||
</div>
|
</div>
|
||||||
<transition-group name="zoom"
|
<transition-group name="zoom"
|
||||||
tag="ul"
|
tag="ul"
|
||||||
@@ -78,10 +80,11 @@ import CardBadges from './CardBadges'
|
|||||||
import Color from '../../mixins/color'
|
import Color from '../../mixins/color'
|
||||||
import labelStyle from '../../mixins/labelStyle'
|
import labelStyle from '../../mixins/labelStyle'
|
||||||
import AttachmentDragAndDrop from '../AttachmentDragAndDrop'
|
import AttachmentDragAndDrop from '../AttachmentDragAndDrop'
|
||||||
|
import CardMenu from './CardMenu'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CardItem',
|
name: 'CardItem',
|
||||||
components: { CardBadges, AttachmentDragAndDrop },
|
components: { CardBadges, AttachmentDragAndDrop, CardMenu },
|
||||||
directives: {
|
directives: {
|
||||||
ClickOutside,
|
ClickOutside,
|
||||||
},
|
},
|
||||||
|
|||||||
171
src/components/cards/CardMenu.vue
Normal file
171
src/components/cards/CardMenu.vue
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<!--
|
||||||
|
- @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||||
|
-
|
||||||
|
- @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
-
|
||||||
|
- @license GNU AGPL version 3 or any later version
|
||||||
|
-
|
||||||
|
- This program is free software: you can redistribute it and/or modify
|
||||||
|
- it under the terms of the GNU Affero General Public License as
|
||||||
|
- published by the Free Software Foundation, either version 3 of the
|
||||||
|
- License, or (at your option) any later version.
|
||||||
|
-
|
||||||
|
- This program is distributed in the hope that it will be useful,
|
||||||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
- GNU Affero General Public License for more details.
|
||||||
|
-
|
||||||
|
- You should have received a copy of the GNU Affero General Public License
|
||||||
|
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div @click.stop.prevent>
|
||||||
|
<Actions v-if="canEdit">
|
||||||
|
<ActionButton v-if="showArchived === false" icon="icon-user" @click="assignCardToMe()">
|
||||||
|
{{ t('deck', 'Assign to me') }}
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton icon="icon-archive" @click="archiveUnarchiveCard()">
|
||||||
|
{{ t('deck', (showArchived ? 'Unarchive card' : 'Archive card')) }}
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton v-if="showArchived === false" icon="icon-delete" @click="deleteCard()">
|
||||||
|
{{ t('deck', 'Delete card') }}
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton icon="icon-external" @click.stop="modalShow=true">
|
||||||
|
{{ t('deck', 'Move card') }}
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton icon="icon-settings-dark" @click="openCard">
|
||||||
|
{{ t('deck', 'Card details') }}
|
||||||
|
</ActionButton>
|
||||||
|
</Actions>
|
||||||
|
</div>
|
||||||
|
<Modal v-if="modalShow" :title="t('deck', 'Move card to another board')" @close="modalShow=false">
|
||||||
|
<div class="modal__content">
|
||||||
|
<h3>{{ t('deck', 'Move card to another board') }}</h3>
|
||||||
|
<Multiselect v-model="selectedBoard"
|
||||||
|
:placeholder="t('deck', 'Select a board')"
|
||||||
|
:options="boards"
|
||||||
|
:max-height="100"
|
||||||
|
label="title"
|
||||||
|
@select="loadStacksFromBoard" />
|
||||||
|
<Multiselect v-model="selectedStack"
|
||||||
|
:placeholder="t('deck', 'Select a stack')"
|
||||||
|
:options="stacksFromBoard"
|
||||||
|
:max-height="100"
|
||||||
|
label="title" />
|
||||||
|
|
||||||
|
<button :disabled="!isBoardAndStackChoosen" class="primary" @click="moveCard">
|
||||||
|
{{ t('deck', 'Move card') }}
|
||||||
|
</button>
|
||||||
|
<button @click="modalShow=false">
|
||||||
|
{{ t('deck', 'Cancel') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { Modal, Actions, ActionButton, Multiselect } from '@nextcloud/vue'
|
||||||
|
import { mapGetters, mapState } from 'vuex'
|
||||||
|
import axios from '@nextcloud/axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CardMenu',
|
||||||
|
components: { Actions, ActionButton, Modal, Multiselect },
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
modalShow: false,
|
||||||
|
selectedBoard: '',
|
||||||
|
selectedStack: '',
|
||||||
|
stacksFromBoard: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters([
|
||||||
|
'canEdit',
|
||||||
|
]),
|
||||||
|
...mapState({
|
||||||
|
showArchived: state => state.showArchived,
|
||||||
|
currentBoard: state => state.currentBoard,
|
||||||
|
}),
|
||||||
|
|
||||||
|
card() {
|
||||||
|
return this.$store.getters.cardById(this.id)
|
||||||
|
},
|
||||||
|
isBoardAndStackChoosen() {
|
||||||
|
if (this.selectedBoard === '' || this.selectedStack === '') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
boards() {
|
||||||
|
return this.$store.getters.boards.filter(board => {
|
||||||
|
return board.id !== this.currentBoard.id
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openCard() {
|
||||||
|
this.$router.push({ name: 'card', params: { cardId: this.id } })
|
||||||
|
},
|
||||||
|
deleteCard() {
|
||||||
|
this.$store.dispatch('deleteCard', this.card)
|
||||||
|
},
|
||||||
|
archiveUnarchiveCard() {
|
||||||
|
this.$store.dispatch('archiveUnarchiveCard', { ...this.card, archived: !this.card.archived })
|
||||||
|
},
|
||||||
|
assignCardToMe() {
|
||||||
|
this.copiedCard = Object.assign({}, this.card)
|
||||||
|
this.$store.dispatch('assignCardToUser', {
|
||||||
|
card: this.copiedCard,
|
||||||
|
assignee: {
|
||||||
|
userId: OC.getCurrentUser().uid,
|
||||||
|
type: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
moveCard() {
|
||||||
|
this.copiedCard = Object.assign({}, this.card)
|
||||||
|
this.copiedCard.stackId = this.selectedStack.id
|
||||||
|
this.$store.dispatch('moveCard', this.copiedCard)
|
||||||
|
this.modalShow = false
|
||||||
|
},
|
||||||
|
async loadStacksFromBoard(board) {
|
||||||
|
try {
|
||||||
|
const url = OC.generateUrl('/apps/deck/stacks/' + board.id)
|
||||||
|
const response = await axios.get(url)
|
||||||
|
this.stacksFromBoard = response.data
|
||||||
|
} catch (err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.modal__content {
|
||||||
|
width: 25vw;
|
||||||
|
min-width: 250px;
|
||||||
|
min-height: 120px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 20px 100px 20px;
|
||||||
|
|
||||||
|
.multiselect {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal__content button {
|
||||||
|
float: right;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user