Skip to content

Commit

Permalink
Add externalApp actions to contextmenu & sidbar actions
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalwengerter committed Sep 29, 2021
1 parent cc6cce4 commit 374ec67
Show file tree
Hide file tree
Showing 10 changed files with 838 additions and 219 deletions.
7 changes: 7 additions & 0 deletions changelog/unreleased/enhancement-external-app-fileactions
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Add AppProvider actions to fileactions

If the AppProvider within oCIS communicates a fitting application
for the mime type of a file, there are now additional actions in
the default actions and actions in both the contextmenu and the right sidebar.

https://github.com/owncloud/web/pull/5805
78 changes: 57 additions & 21 deletions packages/web-app-files/src/components/FilesList/ContextActions.vue
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
<template>
<ul id="oc-files-context-actions" class="uk-list oc-mt-s">
<div id="oc-files-context-menu">
<ul
v-if="showExternalApps"
id="oc-files-context-default-actions"
class="uk-list oc-my-xs oc-files-context-actions"
>
<li v-for="(app, index) in appList" :key="`app-${index}`">
<oc-button
appearance="raw"
class="oc-text-bold"
@click="$_fileActions_openLink(app.name, item.id)"
>
<img :src="app.icon" :alt="`Icon for ${app.name} app`" class="oc-icon oc-icon-m" />
<span class="oc-files-context-action-label">{{ 'Open in ' + app.name }}</span>
</oc-button>
</li>
</ul>
<hr v-if="showExternalApps" />
<template v-for="(section, i) in menuSections">
<li
v-for="(action, j) in section.items"
:key="`section-${section.name}-action-${j}`"
class="oc-files-context-action"
<ul
id="`oc-files-context-actions-${section.name}`"
:key="`section-${section.name}-list`"
class="uk-list oc-mt-s oc-files-context-actions"
>
<component
:is="action.componentType"
v-bind="getComponentProps(action, item)"
:class="['oc-text-bold', action.class]"
v-on="getComponentListeners(action, item)"
<li
v-for="(action, j) in section.items"
:key="`section-${section.name}-action-${j}`"
class="oc-files-context-action"
>
<oc-icon :name="action.icon" size="medium" />
<span class="oc-files-context-action-label">{{ action.label(item) }}</span>
<span
v-if="action.opensInNewWindow"
class="oc-invisible-sr"
v-text="$gettext('(Opens in new window)')"
/>
</component>
</li>
<component
:is="action.componentType"
v-bind="getComponentProps(action, item)"
:class="['oc-text-bold', action.class]"
v-on="getComponentListeners(action, item)"
>
<oc-icon :name="action.icon" size="medium" />
<span class="oc-files-context-action-label">{{ action.label(item) }}</span>
<span
v-if="action.opensInNewWindow"
class="oc-invisible-sr"
v-text="$gettext('(Opens in new window)')"
/>
</component>
</li>
</ul>
<hr v-if="i < menuSections.length - 1" :key="`section-${section.name}-separator`" />
</template>
</ul>
</div>
</template>

<script>
Expand Down Expand Up @@ -71,10 +94,17 @@ export default {
required: true
}
},
data: () => ({
appList: []
}),
computed: {
...mapGetters('Files', ['currentFolder']),
showExternalApps() {
return this.item.extension && this.appList?.length > 0
},
menuSections() {
const sections = []
if (this.menuItemsContext.length) {
Expand Down Expand Up @@ -153,7 +183,13 @@ export default {
return [...this.$_showDetails_items].filter(item => item.isEnabled(this.filterParams))
}
},
mounted() {
this.loadApps()
},
methods: {
loadApps() {
this.appList = this.$_fileActions_loadApps(this.item)
},
getComponentProps(action, resource) {
if (action.componentType === 'router-link' && action.route) {
return {
Expand Down Expand Up @@ -194,7 +230,7 @@ export default {
</script>
<style lang="scss">
#oc-files-context-actions {
.oc-files-context-actions {
text-align: left;
white-space: normal;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
<template>
<ul id="oc-files-actions-sidebar" class="uk-list oc-mt-s">
<li v-for="(app, index) in appList" :key="`app-${index}`" class="oc-py-xs">
<oc-button
appearance="raw"
class="oc-text-bold"
@click="$_fileActions_openLink(app.name, highlightedFile.fileId)"
>
<!-- why img and not oc-icon again? -->
<img :src="app.icon" :alt="`Icon for ${app.name} app`" class="oc-icon oc-icon-m" />
<span class="oc-files-actions-sidebar-action-label">{{ 'Open in ' + app.name }}</span>
</oc-button>
</li>
<li v-for="(action, index) in actions" :key="`action-${index}`" class="oc-py-xs">
<component
:is="action.componentType"
Expand Down Expand Up @@ -32,6 +43,9 @@ export default {
return $gettext('Actions')
},
mixins: [FileActions],
data: () => ({
appList: []
}),
computed: {
...mapGetters('Files', ['highlightedFile', 'currentFolder']),
Expand All @@ -46,7 +60,13 @@ export default {
)
}
},
mounted() {
this.loadApps()
},
methods: {
loadApps() {
this.appList = this.$_fileActions_loadApps(this.highlightedFile)
},
getComponentProps(action, highlightedFile) {
if (action.componentType === 'router-link' && action.route) {
return {
Expand Down
46 changes: 44 additions & 2 deletions packages/web-app-files/src/mixins/fileActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default {
computed: {
...mapState(['apps']),
...mapGetters('Files', ['highlightedFile', 'currentFolder']),
...mapGetters(['configuration']),
...mapGetters(['capabilities', 'configuration']),

$_fileActions_systemActions() {
const systemActions = []
Expand Down Expand Up @@ -92,6 +92,7 @@ export default {
},

methods: {
...mapGetters('External', ['getMimeTypes']),
...mapActions(['openFile']),

$_fileActions_openEditor(editor, filePath, fileId, mode) {
Expand Down Expand Up @@ -135,7 +136,16 @@ export default {
})
},

// TODO: Make user-configurable what is a defaultAction for a filetype/mimetype
// returns the _first_ action from actions array which we now construct from
// available mime-types coming from the app-provider and existing actions
$_fileActions_triggerDefaultAction(resource) {
const availableExternalAppActions = this.$_fileActions_loadApps(resource)

for (const action of availableExternalAppActions) {
action.handler = () => this.$_fileActions_openLink(action.name, resource.fileId)
}

let actions = this.$_fileActions_editorActions.concat(this.$_fileActions_systemActions)

actions = actions.filter(action => {
Expand All @@ -146,7 +156,39 @@ export default {
}) && action.canBeDefault
)
})
actions[0].handler(resource, actions[0].handlerData)

const allDefaultActions = availableExternalAppActions.concat(actions)
allDefaultActions[0].handler(resource, allDefaultActions[0].handlerData)
},

// returns an array of available external Apps
// to open a resource with a specific mimeType
$_fileActions_loadApps(resource) {
const { mimeType } = resource
if (mimeType === undefined || !this.capabilities.files.app_providers) {
return []
}
const allAvailableMimeTypes = this.getMimeTypes()
if (!allAvailableMimeTypes.length) {
return allAvailableMimeTypes
} else {
const availableMimeTypes = allAvailableMimeTypes.find(t => t.mime_type === mimeType)
if (availableMimeTypes) {
return availableMimeTypes.app_providers
} else {
return []
}
}
},

$_fileActions_openLink(appName, resourceId) {
const actionableId = resourceId.replaceAll('=', '')
const routeData = this.$router.resolve({
name: 'external-apps',
params: { app: appName, file_id: actionableId }
})
// TODO: Let users configure whether to open in same/new tab (`_blank` vs `_self`)
window.open(routeData.href, '_blank')
}
}
}
18 changes: 18 additions & 0 deletions packages/web-app-files/tests/__fixtures__/mimeTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default {
'application/fileFormat1': {
app_providers: [
{ name: 'ExampleApp1Name', icon: 'https://www.example-app.com/assets/icon1.png' }
]
},
'application/fileFormat2': {
app_providers: [
{ name: 'ExampleApp2Name', icon: 'https://www.example-app.com/assets/icon2.png' }
]
},
'application/fileFormat3': {
app_providers: [
{ name: 'ExampleApp1Name', icon: 'https://www.example-app.com/assets/icon1.png' },
{ name: 'ExampleApp2Name', icon: 'https://www.example-app.com/assets/icon2.png' }
]
}
}
Loading

0 comments on commit 374ec67

Please sign in to comment.