Merge pull request #2772 from nextcloud/enh/card-actions
Add API to register card actions
This commit is contained in:
@@ -33,10 +33,17 @@
|
|||||||
<ActionButton v-if="cardDetailsInModal" icon="icon-menu-sidebar" @click.stop="showModal()">
|
<ActionButton v-if="cardDetailsInModal" icon="icon-menu-sidebar" @click.stop="showModal()">
|
||||||
{{ t('deck', 'Open in sidebar view') }}
|
{{ t('deck', 'Open in sidebar view') }}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
|
|
||||||
<ActionButton v-else icon="icon-external" @click.stop="showModal()">
|
<ActionButton v-else icon="icon-external" @click.stop="showModal()">
|
||||||
{{ t('deck', 'Open in bigger view') }}
|
{{ t('deck', 'Open in bigger view') }}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
|
|
||||||
|
<ActionButton v-for="action in cardActions"
|
||||||
|
:key="action.label"
|
||||||
|
:close-after-click="true"
|
||||||
|
:icon="action.icon"
|
||||||
|
@click="action.callback(cardRichObject)">
|
||||||
|
{{ action.label }}
|
||||||
|
</ActionButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<AppSidebarTab id="details"
|
<AppSidebarTab id="details"
|
||||||
@@ -73,6 +80,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ActionButton, AppSidebar, AppSidebarTab } from '@nextcloud/vue'
|
import { ActionButton, AppSidebar, AppSidebarTab } from '@nextcloud/vue'
|
||||||
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
import CardSidebarTabDetails from './CardSidebarTabDetails'
|
import CardSidebarTabDetails from './CardSidebarTabDetails'
|
||||||
import CardSidebarTabAttachments from './CardSidebarTabAttachments'
|
import CardSidebarTabAttachments from './CardSidebarTabAttachments'
|
||||||
@@ -114,7 +122,7 @@ export default {
|
|||||||
currentBoard: state => state.currentBoard,
|
currentBoard: state => state.currentBoard,
|
||||||
cardDetailsInModal: state => state.cardDetailsInModal,
|
cardDetailsInModal: state => state.cardDetailsInModal,
|
||||||
}),
|
}),
|
||||||
...mapGetters(['canEdit', 'assignables']),
|
...mapGetters(['canEdit', 'assignables', 'cardActions', 'stackById']),
|
||||||
title() {
|
title() {
|
||||||
return this.titleEditable ? this.titleEditing : this.currentCard.title
|
return this.titleEditable ? this.titleEditing : this.currentCard.title
|
||||||
},
|
},
|
||||||
@@ -124,6 +132,15 @@ export default {
|
|||||||
subtitle() {
|
subtitle() {
|
||||||
return t('deck', 'Modified') + ': ' + this.relativeDate(this.currentCard.lastModified * 1000) + ' ' + t('deck', 'Created') + ': ' + this.relativeDate(this.currentCard.createdAt * 1000)
|
return t('deck', 'Modified') + ': ' + this.relativeDate(this.currentCard.lastModified * 1000) + ' ' + t('deck', 'Created') + ': ' + this.relativeDate(this.currentCard.createdAt * 1000)
|
||||||
},
|
},
|
||||||
|
cardRichObject() {
|
||||||
|
return {
|
||||||
|
id: '' + this.currentCard.id,
|
||||||
|
name: this.currentCard.title,
|
||||||
|
boardname: this.currentBoard.title,
|
||||||
|
stackname: this.stackById(this.currentCard.stackId)?.title,
|
||||||
|
link: window.location.protocol + '//' + window.location.host + generateUrl('/apps/deck/') + `#/board/${this.currentBoard.id}/card/${this.currentCard.id}`,
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleUpdateTitleEditable(value) {
|
handleUpdateTitleEditable(value) {
|
||||||
|
|||||||
37
src/main.js
37
src/main.js
@@ -103,3 +103,40 @@ new Vue({
|
|||||||
},
|
},
|
||||||
render: h => h(App),
|
render: h => h(App),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!window.OCA.Deck) {
|
||||||
|
window.OCA.Deck = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} CardRichObject
|
||||||
|
* @property {string} id
|
||||||
|
* @property {string} name
|
||||||
|
* @property {string} boardname
|
||||||
|
* @property {string} stackname
|
||||||
|
* @property {string} link
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback registerActionCallback
|
||||||
|
* @param {CardRichObject} card
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frontend message API for adding actions to talk messages.
|
||||||
|
* @param {*} Object the wrapping object.
|
||||||
|
* @param {String} label the action label.
|
||||||
|
* @param {registerActionCallback} callback the callback function. This function will receive
|
||||||
|
* the card as a parameter and be triggered by a click on the
|
||||||
|
* action. The card parameter will be of the format of a rich object string
|
||||||
|
* type "deck-card"
|
||||||
|
* @param {String} icon the action label. E.g. "icon-reply"
|
||||||
|
*/
|
||||||
|
window.OCA.Deck.registerCardAction = ({ label, callback, icon }) => {
|
||||||
|
const cardAction = {
|
||||||
|
label,
|
||||||
|
callback,
|
||||||
|
icon,
|
||||||
|
}
|
||||||
|
store.dispatch('addCardAction', cardAction)
|
||||||
|
}
|
||||||
|
|||||||
42
src/store/actions.js
Normal file
42
src/store/actions.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* @copyright Copyright (c) 2021 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
state: {
|
||||||
|
actions: {
|
||||||
|
card: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
cardActions: (state) => state.actions.card,
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
ADD_CARD_ACTION(state, action) {
|
||||||
|
state.actions.card.push(action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async addCardAction({ commit }, action) {
|
||||||
|
commit('ADD_CARD_ACTION', action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ import Vuex from 'vuex'
|
|||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateOcsUrl } from '@nextcloud/router'
|
import { generateOcsUrl } from '@nextcloud/router'
|
||||||
import { BoardApi } from '../services/BoardApi'
|
import { BoardApi } from '../services/BoardApi'
|
||||||
|
import actions from './actions'
|
||||||
import stack from './stack'
|
import stack from './stack'
|
||||||
import card from './card'
|
import card from './card'
|
||||||
import comment from './comment'
|
import comment from './comment'
|
||||||
@@ -47,6 +48,7 @@ export const BOARD_FILTERS = {
|
|||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
modules: {
|
modules: {
|
||||||
|
actions,
|
||||||
stack,
|
stack,
|
||||||
card,
|
card,
|
||||||
comment,
|
comment,
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ export default {
|
|||||||
stacksByBoard: state => (id) => {
|
stacksByBoard: state => (id) => {
|
||||||
return state.stacks.filter((stack) => stack.boardId === id).sort((a, b) => a.order - b.order)
|
return state.stacks.filter((stack) => stack.boardId === id).sort((a, b) => a.order - b.order)
|
||||||
},
|
},
|
||||||
|
stackById: state => (id) => {
|
||||||
|
return state.stacks.find((stack) => stack.id === id)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
addStack(state, stack) {
|
addStack(state, stack) {
|
||||||
|
|||||||
Reference in New Issue
Block a user