Skip to content

Commit 6dd15ac

Browse files
authored
Add default actions extension point (#11515)
* feat: introduce default actions extension point
1 parent d7a3f45 commit 6dd15ac

File tree

13 files changed

+125
-147
lines changed

13 files changed

+125
-147
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Enhancement: Add default actions extension point
2+
3+
We've added a new extension point `global.files.default-action` for allowing action extensions to register themselves for the left click default action.
4+
5+
https://github.com/owncloud/web/pull/11515

docs/extension-system/_index.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,11 @@ your extension will be used automatically.
151151
2. Folder views for regular folders. ExtensionPointId `app.files.folder-views.folder`. Mounts extensions of type `folderView`.
152152
3. Folder views for the project spaces overview. ExtensionPointId `app.files.folder-views.project-spaces`. Mounts extensions of type `folderView`.
153153
4. Folder views for the favorites page. ExtensionPointId `app.files.folder-views.favorites`. Mounts extensions of type `folderView`.
154-
5. Right click context menu. ExtensionPointId `app.files.context-actions`. Mounts extensions of type `action`.
155-
6. Batch actions in the app bar above file lists. ExtensionPointId `app.files.batch-actions`. Mounts extensions of type `action`.
156-
7. Upload menu. ExtensionPointId `app.files.upload-menu`. Mounts extensions of type `action`.
157-
8. Quick actions. ExtensionPointId `app.files.quick-actions`. Mounts extensions of type `action`.
154+
5. Right click context menu. ExtensionPointId `global.files.context-actions`. Mounts extensions of type `action`.
155+
6. Batch actions in the app bar above file lists. ExtensionPointId `global.files.batch-actions`. Mounts extensions of type `action`.
156+
7. Default actions (left click) on a file. ExtensionPointId `global.files.default-actions`. Mounts extensions of type `action`.
157+
8. Upload menu. ExtensionPointId `app.files.upload-menu`. Mounts extensions of type `action`.
158+
9. Quick actions. ExtensionPointId `app.files.quick-actions`. Mounts extensions of type `action`.
158159
4. Global search providers. ExtensionPointId `app.search.providers`. Utilizes extensions of type `search` as search engines for the search input in the global top bar.
159160

160161
#### User Preferences for Extensions

packages/web-app-files/src/components/FilesList/ResourceDetails.vue

+8-14
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Resource, SpaceResource } from '@ownclouders/web-client'
1414
1515
import FileActions from '../SideBar/Actions/FileActions.vue'
1616
import FileDetails from '../SideBar/Details/FileDetails.vue'
17-
import { useFileActions, FileInfo } from '@ownclouders/web-pkg'
17+
import { FileInfo, useOpenWithDefaultApp } from '@ownclouders/web-pkg'
1818
import { useRouteQuery } from '@ownclouders/web-pkg'
1919
2020
export default defineComponent({
@@ -25,6 +25,7 @@ export default defineComponent({
2525
},
2626
provide() {
2727
return {
28+
// provide resource and space for sub-components
2829
resource: computed(() => this.singleResource),
2930
space: computed(() => this.space)
3031
}
@@ -42,20 +43,13 @@ export default defineComponent({
4243
}
4344
},
4445
setup(props) {
45-
const { getDefaultEditorAction } = useFileActions()
46+
const { openWithDefaultApp } = useOpenWithDefaultApp()
4647
const openWithDefaultAppQuery = useRouteQuery('openWithDefaultApp')
47-
const fileActionsOptions = {
48-
resources: [props.singleResource],
49-
space: props.space
50-
}
51-
const defaultEditorAction = getDefaultEditorAction(fileActionsOptions)
52-
53-
if (unref(openWithDefaultAppQuery) === 'true' && defaultEditorAction) {
54-
defaultEditorAction.handler({ ...fileActionsOptions })
55-
}
56-
57-
return {
58-
defaultEditorAction
48+
if (unref(openWithDefaultAppQuery) === 'true') {
49+
openWithDefaultApp({
50+
space: props.space,
51+
resource: props.singleResource
52+
})
5953
}
6054
}
6155
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {
2+
ActionExtension,
3+
useFileActionsCopyQuickLink,
4+
useFileActionsOpenShortcut,
5+
useFileActionsShowShares
6+
} from '@ownclouders/web-pkg'
7+
import {
8+
contextActionsExtensionPoint,
9+
defaultActionsExtensionPoint,
10+
quickActionsExtensionPoint
11+
} from '../../extensionPoints'
12+
import { unref } from 'vue'
13+
14+
export const useFileActions = (): ActionExtension[] => {
15+
const { actions: openShortcutActions } = useFileActionsOpenShortcut()
16+
const { actions: showSharesActions } = useFileActionsShowShares()
17+
const { actions: quickLinkActions } = useFileActionsCopyQuickLink()
18+
19+
return [
20+
{
21+
id: 'com.github.owncloud.web.files.context-action.open-shortcut',
22+
extensionPointIds: [contextActionsExtensionPoint.id, defaultActionsExtensionPoint.id],
23+
type: 'action',
24+
action: unref(openShortcutActions)[0]
25+
},
26+
{
27+
id: 'com.github.owncloud.web.files.quick-action.collaborator',
28+
extensionPointIds: [quickActionsExtensionPoint.id],
29+
type: 'action',
30+
action: unref(showSharesActions)[0]
31+
},
32+
{
33+
id: 'com.github.owncloud.web.files.quick-action.quicklink',
34+
extensionPointIds: [quickActionsExtensionPoint.id],
35+
type: 'action',
36+
action: unref(quickLinkActions)[0]
37+
}
38+
]
39+
}

packages/web-app-files/src/extensionPoints.ts

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export const contextActionsExtensionPoint: ExtensionPoint<ActionExtension> = {
2626
extensionType: 'action',
2727
multiple: true
2828
}
29+
export const defaultActionsExtensionPoint: ExtensionPoint<ActionExtension> = {
30+
id: 'global.files.default-actions',
31+
extensionType: 'action',
32+
multiple: true
33+
}
2934
export const fileSideBarExtensionPoint: ExtensionPoint<SidebarPanelExtension<any, any, any>> = {
3035
id: 'global.files.sidebar',
3136
extensionType: 'sidebarPanel',
@@ -51,6 +56,7 @@ export const extensionPoints = () => {
5156
quickActionsExtensionPoint,
5257
batchActionsExtensionPoint,
5358
contextActionsExtensionPoint,
59+
defaultActionsExtensionPoint,
5460
fileSideBarExtensionPoint,
5561
folderViewsFolderExtensionPoint,
5662
folderViewsFavoritesExtensionPoint,

packages/web-app-files/src/extensions.ts

+4-19
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@ import {
33
Extension,
44
useCapabilityStore,
55
useConfigStore,
6-
useFileActionsCopyQuickLink,
7-
useFileActionsShowShares,
86
useRouter,
97
useSearch,
108
useUserStore
119
} from '@ownclouders/web-pkg'
12-
import { computed, unref } from 'vue'
10+
import { computed } from 'vue'
1311
import { SDKSearch } from './search'
1412
import { useSideBarPanels } from './composables/extensions/useFileSideBars'
1513
import { useFolderViews } from './composables/extensions/useFolderViews'
16-
import { quickActionsExtensionPoint } from './extensionPoints'
14+
import { useFileActions } from './composables/extensions/useFileActions'
1715
import { urlJoin } from '@ownclouders/web-client'
1816

1917
export const extensions = (appInfo: ApplicationInformation) => {
@@ -23,13 +21,12 @@ export const extensions = (appInfo: ApplicationInformation) => {
2321
const router = useRouter()
2422
const { search: searchFunction } = useSearch()
2523

26-
const { actions: showSharesActions } = useFileActionsShowShares()
27-
const { actions: quickLinkActions } = useFileActionsCopyQuickLink()
28-
24+
const fileActionExtensions = useFileActions()
2925
const folderViewExtensions = useFolderViews()
3026
const sideBarPanelExtensions = useSideBarPanels()
3127

3228
return computed<Extension[]>(() => [
29+
...fileActionExtensions,
3330
...folderViewExtensions,
3431
...sideBarPanelExtensions,
3532
{
@@ -38,18 +35,6 @@ export const extensions = (appInfo: ApplicationInformation) => {
3835
type: 'search',
3936
searchProvider: new SDKSearch(capabilityStore, router, searchFunction, configStore)
4037
},
41-
{
42-
id: 'com.github.owncloud.web.files.quick-action.collaborator',
43-
extensionPointIds: [quickActionsExtensionPoint.id],
44-
type: 'action',
45-
action: unref(showSharesActions)[0]
46-
},
47-
{
48-
id: 'com.github.owncloud.web.files.quick-action.quicklink',
49-
extensionPointIds: [quickActionsExtensionPoint.id],
50-
type: 'action',
51-
action: unref(quickLinkActions)[0]
52-
},
5338
...((userStore.user && [
5439
{
5540
id: `app.${appInfo.id}.menuItem`,

packages/web-app-files/tests/unit/components/FilesList/ResourceDetails.spec.ts

+20-21
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,49 @@
1-
import { defaultComponentMocks, defaultPlugins, mount, RouteLocation } from 'web-test-helpers'
1+
import {
2+
defaultComponentMocks,
3+
defaultPlugins,
4+
RouteLocation,
5+
shallowMount
6+
} from 'web-test-helpers'
27
import ResourceDetails from '../../../../src/components/FilesList/ResourceDetails.vue'
38
import { mock } from 'vitest-mock-extended'
4-
import { useFileActions } from '@ownclouders/web-pkg'
59
import { Resource, SpaceResource } from '@ownclouders/web-client'
6-
import { useRouteQuery } from '@ownclouders/web-pkg'
10+
import { useOpenWithDefaultApp, useRouteQuery } from '@ownclouders/web-pkg'
711
import { ref } from 'vue'
812

913
vi.mock('@ownclouders/web-pkg', async (importOriginal) => ({
1014
...(await importOriginal<any>()),
1115
getIndicators: vi.fn(() => []),
1216
useRouteQuery: vi.fn(),
13-
useFileActions: vi.fn()
17+
useOpenWithDefaultApp: vi.fn()
1418
}))
1519

1620
describe('ResourceDetails component', () => {
17-
vi.mocked(useFileActions).mockImplementation(() =>
18-
mock<ReturnType<typeof useFileActions>>({
19-
getDefaultEditorAction: () => ({ handler: vi.fn() }) as any
20-
})
21-
)
22-
23-
it('renders resource details correctly', () => {
24-
const { wrapper } = getWrapper(true)
25-
expect(wrapper.html()).toMatchSnapshot()
26-
})
27-
2821
describe('open with default actions', () => {
2922
it("doesn't open default action if query param 'openWithDefaultApp' isn't set true", () => {
30-
const { wrapper } = getWrapper()
31-
expect(wrapper.vm.defaultEditorAction.handler).not.toHaveBeenCalled()
23+
const { mocks } = getWrapper()
24+
expect(mocks.openWithDefaultAppMock).not.toHaveBeenCalled()
3225
})
3326
it("opens default action if query param 'openWithDefaultApp' is set true", () => {
3427
vi.mocked(useRouteQuery).mockImplementationOnce(() => ref('true'))
35-
const { wrapper } = getWrapper()
36-
expect(wrapper.vm.defaultEditorAction.handler).toHaveBeenCalled()
28+
const { mocks } = getWrapper()
29+
expect(mocks.openWithDefaultAppMock).toHaveBeenCalled()
3730
})
3831
})
3932

4033
function getWrapper(isFolder = false) {
34+
const openWithDefaultAppMock = vi.fn()
35+
vi.mocked(useOpenWithDefaultApp).mockReturnValue({
36+
openWithDefaultApp: openWithDefaultAppMock
37+
})
38+
4139
const mocks = {
4240
...defaultComponentMocks({
4341
currentRoute: mock<RouteLocation>({
4442
name: 'files-public-link',
4543
query: { openWithDefaultAppQuery: 'true' }
4644
})
47-
})
45+
}),
46+
openWithDefaultAppMock
4847
}
4948

5049
const file = {
@@ -64,7 +63,7 @@ describe('ResourceDetails component', () => {
6463

6564
return {
6665
mocks,
67-
wrapper: mount(ResourceDetails, {
66+
wrapper: shallowMount(ResourceDetails, {
6867
props: {
6968
space,
7069
singleResource: file

packages/web-app-files/tests/unit/components/FilesList/__snapshots__/ResourceDetails.spec.ts.snap

-50
This file was deleted.

packages/web-pkg/src/components/FilesList/ContextActions.vue

-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
ActionExtension,
1010
FileActionOptions,
1111
useExtensionRegistry,
12-
useFileActionsOpenShortcut,
1312
useFileActionsToggleHideShare,
1413
useFileActionsCopyQuickLink,
1514
useFileActionsPaste,
@@ -64,7 +63,6 @@ export default defineComponent({
6463
const { actions: showDetailsActions } = useFileActionsShowDetails()
6564
const { actions: createSpaceFromResourceActions } = useFileActionsCreateSpaceFromResource()
6665
const { actions: showSharesActions } = useFileActionsShowShares()
67-
const { actions: openShortcutActions } = useFileActionsOpenShortcut()
6866
6967
const extensionRegistry = useExtensionRegistry()
7068
const extensionsContextActions = computed(() => {
@@ -112,7 +110,6 @@ export default defineComponent({
112110
113111
const menuItemsContext = computed(() => {
114112
return [
115-
...unref(openShortcutActions),
116113
...unref(editorActions),
117114
...unref(extensionsContextActions).filter((a) => a.category === 'context')
118115
]

0 commit comments

Comments
 (0)