Skip to content

Commit

Permalink
feat(files): add sidebar action
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Apr 19, 2023
1 parent 85b697a commit 66da58f
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 7 deletions.
50 changes: 50 additions & 0 deletions apps/files/src/actions/sidebarAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license AGPL-3.0-or-later
*
* 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/>.
*
*/
import { translate as t } from '@nextcloud/l10n'
import InformationSvg from '@mdi/svg/svg/information-variant.svg?raw'
import type { Node } from '@nextcloud/files'

import { registerFileAction, FileAction } from '../services/FileAction.ts'
import logger from '../logger.js'

registerFileAction(new FileAction({
id: 'details',
displayName: () => t('files', 'Details'),
iconSvgInline: () => InformationSvg,

enabled: () => !!window?.OCA?.Files?.Sidebar,

async exec(node: Node) {
try {
// TODO: migrate Sidebar to use a Node instead
window?.OCA?.Files?.Sidebar?.open?.(node.path)

return null
} catch (error) {
logger.error('Error while opening sidebar', { error })
return false
}
},

default: true,
order: -50,
}))
26 changes: 24 additions & 2 deletions apps/files/src/components/FileEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
<!-- Menu actions -->
<NcActions v-if="active"
ref="actionsMenu"
:boundaries-element="boundariesElement"
:container="boundariesElement"
:disabled="source._loading"
:force-title="true"
:inline="enabledInlineActions.length"
Expand All @@ -91,15 +93,17 @@
<!-- Size -->
<td v-if="isSizeAvailable"
:style="{ opacity: sizeOpacity }"
class="files-list__row-size">
class="files-list__row-size"
@click="execDefaultAction">
<span>{{ size }}</span>
</td>

<!-- View columns -->
<td v-for="column in columns"
:key="column.id"
:class="`files-list__row-${currentView?.id}-${column.id}`"
class="files-list__row-column-custom">
class="files-list__row-column-custom"
@click="execDefaultAction">
<CustomElementRender v-if="active"
:current-view="currentView"
:render="column.render"
Expand Down Expand Up @@ -202,6 +206,7 @@ export default Vue.extend({
return {
backgroundFailed: false,
backgroundImage: '',
boundariesElement: document.querySelector('.app-content > .files-list'),
loading: '',
}
},
Expand Down Expand Up @@ -323,6 +328,11 @@ export default Vue.extend({
...this.enabledActions.filter(action => !action.inline),
]
},
enabledDefaultActions() {
return [
...this.enabledActions.filter(action => action.default),
]
},
openedMenu: {
get() {
return this.actionsMenuStore.opened === this.uniqueId
Expand Down Expand Up @@ -472,6 +482,12 @@ export default Vue.extend({
Vue.set(this.source, '_loading', true)
const success = await action.exec(this.source, this.currentView)
// If the action returns null, we stay silent
if (success === null) {
return
}
if (success) {
showSuccess(this.t('files', '"{displayName}" action executed successfully', { displayName }))
return
Expand All @@ -486,6 +502,12 @@ export default Vue.extend({
Vue.set(this.source, '_loading', false)
}
},
execDefaultAction() {
if (this.enabledDefaultActions.length > 0) {
// Execute the first default action if any
this.enabledDefaultActions[0].exec(this.source, this.currentView)
}
},
onSelectionChange(selection) {
const newSelectedIndex = this.index
Expand Down
11 changes: 9 additions & 2 deletions apps/files/src/components/FilesListHeaderActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,18 @@ export default Vue.extend({
// Dispatch action execution
const results = await action.execBatch(this.nodes, this.currentView)
// Check if all actions returned null
if (results.filter(result => result !== null).length === 0) {
// If the actions returned null, we stay silent
this.selectionStore.reset()
return
}
// Handle potential failures
if (results.some(result => result !== true)) {
if (results.some(result => result === false)) {
// Remove the failed ids from the selection
const failedIds = selectionIds
.filter((fileid, index) => results[index] !== true)
.filter((fileid, index) => results[index] === false)
this.selectionStore.set(failedIds)
showError(this.t('files', '"{displayName}" failed on some elements ', { displayName }))
Expand Down
1 change: 1 addition & 0 deletions apps/files/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import './templates.js'
import './legacy/filelistSearch.js'
import './actions/deleteAction.ts'
import './actions/favoriteAction.ts'
import './actions/sidebarAction.ts'

import processLegacyFilesViews from './legacy/navigationMapper.js'
import registerFavoritesView from './views/favorites.ts'
Expand Down
7 changes: 4 additions & 3 deletions apps/files/src/services/FileAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ interface FileActionData {
* @returns true if the action was executed, false otherwise
* @throws Error if the action failed
*/
exec: (file: Node, view) => Promise<boolean>,
exec: (file: Node, view) => Promise<boolean|null>,
/**
* Function executed on multiple files action
* @returns true if the action was executed, false otherwise
* @returns true if the action was executed successfully,
* false otherwise and null if the action is silent/undefined.
* @throws Error if the action failed
*/
execBatch?: (files: Node[], view) => Promise<boolean[]>
execBatch?: (files: Node[], view) => Promise<(boolean|null)[]>
/** This action order in the list */
order?: number,
/** Make this action the default */
Expand Down

0 comments on commit 66da58f

Please sign in to comment.