mirror of
https://github.com/nextcloud/server.git
synced 2026-06-08 08:16:43 -04:00
feat(files): support nested actions
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
This commit is contained in:
parent
1d568a89a4
commit
72ffd4999a
2 changed files with 132 additions and 18 deletions
|
|
@ -39,20 +39,56 @@
|
|||
:force-name="true"
|
||||
:force-menu="enabledInlineActions.length === 0 /* forceMenu only if no inline actions */"
|
||||
:inline="enabledInlineActions.length"
|
||||
:open.sync="openedMenu">
|
||||
<NcActionButton v-for="action in enabledMenuActions"
|
||||
:key="action.id"
|
||||
:class="'files-list__row-action-' + action.id"
|
||||
:close-after-click="true"
|
||||
:data-cy-files-list-row-action="action.id"
|
||||
:title="action.title?.([source], currentView)"
|
||||
@click="onActionClick(action)">
|
||||
<template #icon>
|
||||
<NcLoadingIcon v-if="loading === action.id" :size="18" />
|
||||
<NcIconSvgWrapper v-else :svg="action.iconSvgInline([source], currentView)" />
|
||||
</template>
|
||||
{{ actionDisplayName(action) }}
|
||||
</NcActionButton>
|
||||
:open.sync="openedMenu"
|
||||
@close="openedSubmenu = null">
|
||||
<!-- Default actions list-->
|
||||
<template>
|
||||
<NcActionButton v-for="action in enabledMenuActions"
|
||||
:key="action.id"
|
||||
:class="{
|
||||
[`files-list__row-action-${action.id}`]: true,
|
||||
[`files-list__row-action--menu`]: isMenu(action.id)
|
||||
}"
|
||||
:close-after-click="!isMenu(action.id)"
|
||||
:data-cy-files-list-row-action="action.id"
|
||||
:title="action.title?.([source], currentView)"
|
||||
@click="onActionClick(action)">
|
||||
<template #icon>
|
||||
<ChevronRightIcon v-if="isMenu(action.id)" />
|
||||
<NcLoadingIcon v-else-if="loading === action.id" :size="18" />
|
||||
<NcIconSvgWrapper v-else :svg="action.iconSvgInline([source], currentView)" />
|
||||
</template>
|
||||
{{ actionDisplayName(action) }}
|
||||
</NcActionButton>
|
||||
</template>
|
||||
|
||||
<!-- Submenu actions list-->
|
||||
<template v-if="openedSubmenu && enabledSubmenuActions[openedSubmenu]">
|
||||
<!-- Back to top-level button -->
|
||||
<NcActionButton class="files-list__row-action-back" @click="openedSubmenu = ''">
|
||||
<template #icon>
|
||||
<ArrowLeftIcon />
|
||||
</template>
|
||||
{{ t('files', 'Back') }}
|
||||
</NcActionButton>
|
||||
<NcActionSeparator />
|
||||
|
||||
<!-- Submenu actions -->
|
||||
<NcActionButton v-for="action in enabledSubmenuActions[openedSubmenu]"
|
||||
:key="action.id"
|
||||
:class="`files-list__row-action-${action.id}`"
|
||||
class="files-list__row-action--submenu"
|
||||
:close-after-click="true"
|
||||
:data-cy-files-list-row-action="action.id"
|
||||
:title="action.title?.([source], currentView)"
|
||||
@click="onActionClick(action)">
|
||||
<template #icon>
|
||||
<NcLoadingIcon v-if="loading === action.id" :size="18" />
|
||||
<NcIconSvgWrapper v-else :svg="action.iconSvgInline([source], currentView)" />
|
||||
</template>
|
||||
{{ actionDisplayName(action) }}
|
||||
</NcActionButton>
|
||||
</template>
|
||||
</NcActions>
|
||||
</td>
|
||||
</template>
|
||||
|
|
@ -63,8 +99,11 @@ import { showError, showSuccess } from '@nextcloud/dialogs'
|
|||
import { translate as t } from '@nextcloud/l10n';
|
||||
import Vue, { PropType } from 'vue'
|
||||
|
||||
import ArrowLeftIcon from 'vue-material-design-icons/ArrowLeft.vue'
|
||||
import ChevronRightIcon from 'vue-material-design-icons/ChevronRight.vue'
|
||||
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
|
||||
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
|
||||
import NcActionSeparator from '@nextcloud/vue/dist/Components/NcActionSeparator.js'
|
||||
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
|
||||
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
|
||||
|
||||
|
|
@ -78,11 +117,14 @@ export default Vue.extend({
|
|||
name: 'FileEntryActions',
|
||||
|
||||
components: {
|
||||
ArrowLeftIcon,
|
||||
ChevronRightIcon,
|
||||
CustomElementRender,
|
||||
NcActionButton,
|
||||
NcActions,
|
||||
NcActionSeparator,
|
||||
NcIconSvgWrapper,
|
||||
NcLoadingIcon,
|
||||
CustomElementRender,
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -108,8 +150,9 @@ export default Vue.extend({
|
|||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
data() {
|
||||
return {
|
||||
openedSubmenu: '',
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -159,7 +202,13 @@ export default Vue.extend({
|
|||
|
||||
// Actions shown in the menu
|
||||
enabledMenuActions() {
|
||||
return [
|
||||
// If we're in a submenu, only render the inline
|
||||
// actions before the filtered submenu
|
||||
if (this.openedSubmenu) {
|
||||
return this.enabledInlineActions
|
||||
}
|
||||
|
||||
const actions = [
|
||||
// Showing inline first for the NcActions inline prop
|
||||
...this.enabledInlineActions,
|
||||
// Then the rest
|
||||
|
|
@ -168,6 +217,24 @@ export default Vue.extend({
|
|||
// Then we filter duplicates to prevent inline actions to be shown twice
|
||||
return index === self.findIndex(action => action.id === value.id)
|
||||
})
|
||||
|
||||
// Generate list of all top-level actions ids
|
||||
const topActionsIds = actions.filter(action => !action.parent).map(action => action.id) as string[]
|
||||
|
||||
// Filter actions that are not top-level AND have a valid parent
|
||||
return actions.filter(action => !(action.parent && topActionsIds.includes(action.parent)))
|
||||
},
|
||||
|
||||
enabledSubmenuActions() {
|
||||
return this.enabledActions
|
||||
.filter(action => action.parent)
|
||||
.reduce((arr, action) => {
|
||||
if (!arr[action.parent]) {
|
||||
arr[action.parent] = []
|
||||
}
|
||||
arr[action.parent].push(action)
|
||||
return arr
|
||||
}, {} as Record<string, FileAction>)
|
||||
},
|
||||
|
||||
openedMenu: {
|
||||
|
|
@ -201,6 +268,12 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
async onActionClick(action) {
|
||||
// If the action is a submenu, we open it
|
||||
if (this.enabledSubmenuActions[action.id]) {
|
||||
this.openedSubmenu = action.id
|
||||
return
|
||||
}
|
||||
|
||||
const displayName = action.displayName([this.source], this.currentView)
|
||||
try {
|
||||
// Set the loading marker
|
||||
|
|
@ -237,6 +310,10 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
|
||||
isMenu(id: string) {
|
||||
return this.enabledSubmenuActions[id]?.length > 0
|
||||
},
|
||||
|
||||
t,
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import { addNewFileMenuEntry, registerFileAction } from '@nextcloud/files'
|
||||
import MenuIcon from '@mdi/svg/svg/sun-compass.svg?raw'
|
||||
import { FileAction, addNewFileMenuEntry, registerFileAction } from '@nextcloud/files'
|
||||
|
||||
import { action as deleteAction } from './actions/deleteAction'
|
||||
import { action as downloadAction } from './actions/downloadAction'
|
||||
|
|
@ -62,3 +63,39 @@ registerRecentView()
|
|||
|
||||
// Register preview service worker
|
||||
registerPreviewServiceWorker()
|
||||
|
||||
registerFileAction(new FileAction({
|
||||
id: 'menu',
|
||||
displayName: () => 'Menu',
|
||||
iconSvgInline: () => MenuIcon,
|
||||
exec: async () => true,
|
||||
}))
|
||||
|
||||
registerFileAction(new FileAction({
|
||||
id: 'submenu1',
|
||||
displayName: () => 'Submenu 1',
|
||||
iconSvgInline: () => MenuIcon,
|
||||
exec: async () => alert('Hello 1'),
|
||||
parent: 'menu',
|
||||
}))
|
||||
registerFileAction(new FileAction({
|
||||
id: 'submenu2',
|
||||
displayName: () => 'Submenu 2',
|
||||
iconSvgInline: () => MenuIcon,
|
||||
exec: async () => alert('Hello 2'),
|
||||
parent: 'menu',
|
||||
}))
|
||||
registerFileAction(new FileAction({
|
||||
id: 'submenu3',
|
||||
displayName: () => 'Submenu 3',
|
||||
iconSvgInline: () => MenuIcon,
|
||||
exec: async () => alert('Hello 3'),
|
||||
parent: 'menu',
|
||||
}))
|
||||
registerFileAction(new FileAction({
|
||||
id: 'submenu4',
|
||||
displayName: () => 'Submenu 4',
|
||||
iconSvgInline: () => MenuIcon,
|
||||
exec: async () => alert('Hello 4'),
|
||||
parent: 'menu',
|
||||
}))
|
||||
|
|
|
|||
Loading…
Reference in a new issue